Sqlserver数据库分页查询一直是Sqlserver的短板,闲来无事,想出几种方法,假设有表ARTICLE,字段ID、YEAR...(其他省略),数据53210条(客户真实数据,量不大),分页查询每页30条,查询第1500页(即第45001-45030条数据),字段ID聚集索引,YEAR无索引,Sqlserver版本:2008R2
 
 

第一种方案、最简单、普通的方法:

代码如下:
  1. SELECT TOP 30 * FROM ARTICLE WHERE ID NOT IN(SELECT TOP 45000 ID FROM ARTICLE ORDER BY YEAR DESC, ID DESC) ORDER BY YEAR DESC,ID DESC
SELECT TOP 30 * FROM ARTICLE WHERE ID NOT IN(SELECT TOP 45000 ID FROM ARTICLE ORDER BY YEAR DESC, ID DESC) ORDER BY YEAR DESC,ID DESC

平均查询100次所需时间:45s

第二种方案:

代码如下:

  1. SELECT * FROM (  SELECT TOP 30 * FROM (SELECT TOP 45030 * FROM ARTICLE ORDER BY YEAR DESC, ID DESC) f ORDER BY f.YEAR ASC, f.ID DESC) s ORDER BY s.YEAR DESC,s.ID DESC
SELECT * FROM (  SELECT TOP 30 * FROM (SELECT TOP 45030 * FROM ARTICLE ORDER BY YEAR DESC, ID DESC) f ORDER BY f.YEAR ASC, f.ID DESC) s ORDER BY s.YEAR DESC,s.ID DESC 

平均查询100次所需时间:138S

第三种方案:

代码如下:

  1. SELECT * FROM ARTICLE w1,
  2. (
  3. SELECT TOP 30 ID FROM
  4. (
  5. SELECT TOP 50030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
  6. ) w ORDER BY w.YEAR ASC, w.ID ASC
  7. ) w2 WHERE w1.ID = w2.ID ORDER BY w1.YEAR DESC, w1.ID DESC
SELECT * FROM ARTICLE w1,
(
SELECT TOP 30 ID FROM
(
SELECT TOP 50030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
) w ORDER BY w.YEAR ASC, w.ID ASC
) w2 WHERE w1.ID = w2.ID ORDER BY w1.YEAR DESC, w1.ID DESC

平均查询100次所需时间:21S

第四种方案:

代码如下:
  1. SELECT * FROM ARTICLE w1
  2. WHERE ID in
  3. (
  4. SELECT top 30 ID FROM
  5. (
  6. SELECT top 45030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
  7. ) w ORDER BY w.YEAR ASC, w.ID ASC
  8. )
  9. ORDER BY w1.YEAR DESC, w1.ID DESC
SELECT * FROM ARTICLE w1
WHERE ID in
(
SELECT top 30 ID FROM
(
SELECT top 45030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
) w ORDER BY w.YEAR ASC, w.ID ASC
)
ORDER BY w1.YEAR DESC, w1.ID DESC

平均查询100次所需时间:20S

第五种方案:

代码如下:

  1. SELECT w2.n, w1.* FROM ARTICLE w1, (  SELECT TOP 50030 row_number() OVER (ORDER BY YEAR DESC, ID DESC) n, ID FROM ARTICLE ) w2 WHERE w1.ID = w2.ID AND w2.n > 50000 ORDER BY w2.n ASC
SELECT w2.n, w1.* FROM ARTICLE w1, (  SELECT TOP 50030 row_number() OVER (ORDER BY YEAR DESC, ID DESC) n, ID FROM ARTICLE ) w2 WHERE w1.ID = w2.ID AND w2.n > 50000 ORDER BY w2.n ASC 

平均查询100次所需时间:15S

查询第1000-1030条记录

第一种方案:

代码如下:

  1. SELECT TOP 30 * FROM ARTICLE WHERE ID NOT IN(SELECT TOP 1000 ID FROM ARTICLE ORDER BY YEAR DESC, ID DESC) ORDER BY YEAR DESC,ID DESC
SELECT TOP 30 * FROM ARTICLE WHERE ID NOT IN(SELECT TOP 1000 ID FROM ARTICLE ORDER BY YEAR DESC, ID DESC) ORDER BY YEAR DESC,ID DESC 

平均查询100次所需时间:80s

第二种方案:

代码如下:

  1. SELECT * FROM  (   SELECT TOP 30 * FROM (SELECT TOP 1030 * FROM ARTICLE ORDER BY YEAR DESC, ID DESC) f ORDER BY f.YEAR ASC, f.ID DESC) s ORDER BY s.YEAR DESC,s.ID DESC
SELECT * FROM  (   SELECT TOP 30 * FROM (SELECT TOP 1030 * FROM ARTICLE ORDER BY YEAR DESC, ID DESC) f ORDER BY f.YEAR ASC, f.ID DESC) s ORDER BY s.YEAR DESC,s.ID DESC 

平均查询100次所需时间:30S

第三种方案:

代码如下:
  1. SELECT * FROM ARTICLE w1,
  2. (
  3. SELECT TOP 30 ID FROM
  4. (
  5. SELECT TOP 1030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
  6. ) w ORDER BY w.YEAR ASC, w.ID ASC
  7. ) w2 WHERE w1.ID = w2.ID ORDER BY w1.YEAR DESC, w1.ID DESC
SELECT * FROM ARTICLE w1,
(
SELECT TOP 30 ID FROM
(
SELECT TOP 1030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
) w ORDER BY w.YEAR ASC, w.ID ASC
) w2 WHERE w1.ID = w2.ID ORDER BY w1.YEAR DESC, w1.ID DESC

平均查询100次所需时间:12S

第四种方案:

代码如下:
  1. SELECT * FROM ARTICLE w1
  2. WHERE ID in
  3. (
  4. SELECT top 30 ID FROM
  5. (
  6. SELECT top 1030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
  7. ) w ORDER BY w.YEAR ASC, w.ID ASC
  8. )
  9. ORDER BY w1.YEAR DESC, w1.ID DESC
SELECT * FROM ARTICLE w1
WHERE ID in
(
SELECT top 30 ID FROM
(
SELECT top 1030 ID, YEAR FROM ARTICLE ORDER BY YEAR DESC, ID DESC
) w ORDER BY w.YEAR ASC, w.ID ASC
)
ORDER BY w1.YEAR DESC, w1.ID DESC

平均查询100次所需时间:13S

第五种方案:

代码如下:

  1. SELECT w2.n, w1.* FROM ARTICLE w1,(   SELECT TOP 1030 row_number() OVER (ORDER BY YEAR DESC, ID DESC) n, ID FROM ARTICLE) w2 WHERE w1.ID = w2.ID AND w2.n > 1000 ORDER BY w2.n ASC
SELECT w2.n, w1.* FROM ARTICLE w1,(   SELECT TOP 1030 row_number() OVER (ORDER BY YEAR DESC, ID DESC) n, ID FROM ARTICLE) w2 WHERE w1.ID = w2.ID AND w2.n > 1000 ORDER BY w2.n ASC 

平均查询100次所需时间:14S

由此可见在查询页数靠前时,效率3>4>5>2>1,页码靠后时5>4>3>1>2,再根据用户习惯,一般用户的检索只看最前面几页,因此选择3 4 5方案均可,若综合考虑方案5是最好的选择,但是要注意SQL2000不支持row_number()函数,由于时间和条件的限制没有做更深入、范围更广的测试,有兴趣的可以仔细研究下。

以下是根据第四种方案编写的一个分页存储过程:

代码如下:
  1. if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[sys_Page_v2]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
  2. drop procedure [dbo].[sys_Page_v2]
  3. GO
  4. CREATE PROCEDURE [dbo].[sys_Page_v2]
  5. @PCount int output,    --总页数输出
  6. @RCount int output,    --总记录数输出
  7. @sys_Table nvarchar(100),    --查询表名
  8. @sys_Key varchar(50),        --主键
  9. @sys_Fields nvarchar(500),    --查询字段
  10. @sys_Where nvarchar(3000),    --查询条件
  11. @sys_Order nvarchar(100),    --排序字段
  12. @sys_Begin int,        --开始位置
  13. @sys_PageIndex int,        --当前页数
  14. @sys_PageSize int        --页大小
  15. AS
  16. SET NOCOUNT ON
  17. SET ANSI_WARNINGS ON
  18. IF @sys_PageSize < 0 OR @sys_PageIndex < 0
  19. BEGIN
  20. RETURN
  21. END
  22. DECLARE @new_where1 NVARCHAR(3000)
  23. DECLARE @new_order1 NVARCHAR(100)
  24. DECLARE @new_order2 NVARCHAR(100)
  25. DECLARE @Sql NVARCHAR(4000)
  26. DECLARE @SqlCount NVARCHAR(4000)
  27. DECLARE @Top int
  28. if(@sys_Begin <=0)
  29. set @sys_Begin=0
  30. else
  31. set @sys_Begin=@sys_Begin-1
  32. IF ISNULL(@sys_Where,'') = ''
  33. SET @new_where1 = ' '
  34. ELSE
  35. SET @new_where1 = ' WHERE ' + @sys_Where
  36. IF ISNULL(@sys_Order,'') <> ''
  37. BEGIN
  38. SET @new_order1 = ' ORDER BY ' + Replace(@sys_Order,'desc','')
  39. SET @new_order1 = Replace(@new_order1,'asc','desc')
  40. SET @new_order2 = ' ORDER BY ' + @sys_Order
  41. END
  42. ELSE
  43. BEGIN
  44. SET @new_order1 = ' ORDER BY ID DESC'
  45. SET @new_order2 = ' ORDER BY ID ASC'
  46. END
  47. SET @SqlCount = 'SELECT @RCount=COUNT(1),@PCount=CEILING((COUNT(1)+0.0)/'
  48. + CAST(@sys_PageSize AS NVARCHAR)+') FROM ' + @sys_Table + @new_where1
  49. EXEC SP_EXECUTESQL @SqlCount,N'@RCount INT OUTPUT,@PCount INT OUTPUT',
  50. @RCount OUTPUT,@PCount OUTPUT
  51. IF @sys_PageIndex > CEILING((@RCount+0.0)/@sys_PageSize)    --如果输入的当前页数大于实际总页数,则把实际总页数赋值给当前页数
  52. BEGIN
  53. SET @sys_PageIndex =  CEILING((@RCount+0.0)/@sys_PageSize)
  54. END
  55. set @sql = 'select '+ @sys_fields +' from ' + @sys_Table + ' w1 '
  56. + ' where '+ @sys_Key +' in ('
  57. +'select top '+ ltrim(str(@sys_PageSize)) +' ' + @sys_Key + ' from '
  58. +'('
  59. +'select top ' + ltrim(STR(@sys_PageSize * @sys_PageIndex + @sys_Begin)) + ' ' + @sys_Key + ' FROM '
  60. + @sys_Table + @new_where1 + @new_order2
  61. +') w ' + @new_order1
  62. +') ' + @new_order2
  63. print(@sql)
  64. Exec(@sql)
  65. GO

Sqlserver数据库分页查询的更多相关文章

  1. MySQL、SqlServer、Oracle三大主流数据库分页查询

    在这里主要讲解一下MySQL.SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法.可能会有人说这些网上都有,但我的主要目的是把这些知识通过我实际的应用 ...

  2. MySQL、SqlServer、Oracle三大主流数据库分页查询 (MySQL分页不能用top,因为不支持)

    一. MySQL 数据库 分页查询MySQL数据库实现分页比较简单,提供了 LIMIT函数.一般只需要直接写到sql语句后面就行了.LIMIT子 句可以用来限制由SELECT语句返回过来的数据数量,它 ...

  3. Oracle、MySql、SQLServer数据分页查询

    看过此博文后Oracle.MySql.SQLServer 数据分页查询,在根据公司的RegionRes表格做出了 SQLserver的分页查询语句: 别名.字段 FROM( SELECT row_nu ...

  4. JavaWeb分页显示内容之分页查询的三种思路(数据库分页查询)

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6134851.html 在开发过程中,经常做的一件事,也是最基本的事,就是从数据库中查询数据,然后在客户端显示出 ...

  5. MySQL 数据库 分页查询

    在使用MySQL 进行数据库分页查询的时候最主要是使用LIMIT子句进行查询: 首先来看一下LIMIT: LIMIT子句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如果给出两 ...

  6. Oracle 数据库分页查询的三种方法

    一.Oracle 数据库分页查询的三种方法 1.简介 不能对 rownum 使用 >(大于或等于 1 的数值).>=(大于 1 的数值).=(不等于 1 的数值),否则无结果.所以直接用 ...

  7. java 分页对象以及数据库分页查询

    import java.util.List; public class Pager<T> { private Integer pageSize; private Integer total ...

  8. Oracle、MySql、SQLServer 数据分页查询

    最近简单的对oracle,mysql,sqlserver2005的数据分页查询作了研究,把各自的查询的语句贴出来供大家学习..... (一). mysql的分页查询 mysql的分页查询是最简单的,借 ...

  9. mysql、sql server、oracle数据库分页查询及分析(操作手册)

    1.mysql分页查询 方式1: select * from table order by id limit m, n; 该语句的意思为,查询m+n条记录,去掉前m条,返回后n条记录.无疑该查询能够实 ...

随机推荐

  1. 【转载】Powershell在世纪互联Office365中批量将用户添加到组

    $NewUserPath = ".\Office365AddUserToGroup.csv" $NewUsers = import-csv $NewUserPath foreach ...

  2. Ios拦截手机短信程序

    引用 1.手机要越狱,没有越狱的话,下面的可以不用看了!  2.IOS 要5.0以上,4.xx的同上  首先,声明下!由于公司移动开发的项目中,需要根据手机的内容进行逻辑处理,也就是要实现手机短信拦截 ...

  3. 深入理解ThreadLocal(一)

    Android里,在不同的线程(假设子线程已经创建了Looper)中创建Handler时,并不需要显式指定Looper,系统能自动找到该线程自己的Looper.不同线程的Looper相互独立,之所以能 ...

  4. 屌丝IT男

    偶尔翻到豆瓣里一篇对中国屌丝的批评,突然想到当年美国那个垮掉的一代,吸毒,淫乱,绝望的生存,而如今我们苦逼的80后自诩为屌丝的时候,也不想想每一个堕落的时代还是有牛逼的人存在,中国的大学,绝大部分在逃 ...

  5. Careercup - Facebook面试题 - 6139456847347712

    2014-05-01 01:50 题目链接 原题: Microsoft Excel numbers cells ... and after that AA, AB.... AAA, AAB...ZZZ ...

  6. [转载+原创]Emgu CV on C# (三) —— Emgu CV on 均衡化

    本文简要描述了均衡化原理及数学实现等理论问题,最终利用emgucv实现图像的灰度均衡. 直方图的均衡化,这是图像增强的常用方法. 一.均衡化原理及数学实现(转载) 均衡化原理及数学实现可重点参看——& ...

  7. javascript_22_for_二维数组

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  8. 视频学习_css基础学习

    块状元素 block element 容器元素  设置高宽 width height  可以容纳 文本 内脸 和其他块状 霸道  独占一行 特例:form  只容纳 块状元素 常见元素 http:// ...

  9. java.lang.UnsatisfiedLinkError: D:\Tomcat-7.0.59\apache-tomcat-7.0.59\bin\tcnative-1.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform

    今日上午用Tomcat运行一个小项目,报出以下异常信息: java.lang.UnsatisfiedLinkError: D:\Tomcat-7.0.59\apache-tomcat-7.0.59\b ...

  10. fork 函数 和vfork 函数的区别

    问题描述:         fork 函数 和vfork 函数的区别 问题解决: fork函数使用: 注:         以上printf 属于标准IO库带缓冲,如果标准输出链接到终端设备,则它是行 ...