USE tempdb
GO
SET NOCOUNT ON --创建表结构
IF OBJECT_ID(N'ClassB', N'U') IS NOT NULL
DROP TABLE ClassB
GO
CREATE TABLE ClassB(ID INT PRIMARY KEY, Name VARCHAR(16), CreateDate DATETIME, AID INT, Status INT)
CREATE INDEX IDX_CreateDate ON ClassB(CreateDate)
CREATE INDEX IDX_AID ON ClassB(AID)
GO --插入测试数据
DECLARE @ID INT
SET @ID = 1
WHILE @ID <= 100000
BEGIN
INSERT INTO ClassB VALUES(@ID, 'fx', GETDATE(), @ID % 20, @ID % 20)
SET @ID = @ID + 1
END --统计总行数
SELECT 'ClassB' AS ClassB, count(1) AS Count FROM ClassB

查询条件如下:根据CreateDate倒序排序,CreateDate一致时按照ID倒序;时间区间在2014-07-13和2014-07-14之间;每页20条,当前页数第3页;

方案A:双Top,取出之前页的所有ID后,使用NOT IN排除这些ID进行查询,这是性能最差一种,因为他使用相同的查询谓词,查询了两次数据,且两次排序;

DECLARE @page_size INT = 20;
DECLARE @page_index INT = 3;
--A: 双Top:取出之前页的所有ID后,使用NOT IN排除这些ID进行查询,性能最差
WITH ID_List_Excluded AS
(
SELECT TOP (@page_size * (@page_index - 1)) ID FROM ClassB WHERE CreateDate BETWEEN '2014-07-13' AND '2014-07-14'
ORDER BY CreateDate DESC, ID DESC
)
SELECT TOP (@page_size) * FROM ClassB WHERE ID NOT IN (SELECT ID FROM ID_List_Excluded) AND CreateDate BETWEEN '2014-07-13' AND '2014-07-14'
ORDER BY CreateDate DESC, ID DESC;

表 'ClassB'。扫描计数 2,逻辑读取 136 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'Worktable'。扫描计数 1,逻辑读取 197 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

查询页数越靠后逻辑读取,下面是查询第30页的逻辑读取情况:

表 'ClassB'。扫描计数 2,逻辑读取 1243 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

表 'Worktable'。扫描计数 1,逻辑读取 2574 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

方案B:ROW_NUMBER,取出截止到当前页所有符合查询谓词的记录,并给每条记录加上序号,然后根据序号查询,性能次之;

DECLARE @page_size INT = 20;
DECLARE @page_index INT = 3;
--B: ROW_NUMBER:取出截至到当前页所有符合查询谓词的记录,并给每条记录加上序号,然后根据序号查询,性能次之
WITH NewClassB AS
(
SELECT TOP (@page_size * @page_index) ROW_NUMBER() OVER (ORDER BY CreateDate DESC, ID DESC) AS ROWID, * FROM ClassB
WHERE CreateDate BETWEEN '2014-07-13' AND '2014-07-14'
)
SELECT TOP (@page_size) * FROM NewClassB
WHERE ROWID BETWEEN (@page_size * (@page_index - 1) + 1) AND (@page_size * @page_index);

表 'ClassB'。扫描计数 1,逻辑读取 134 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

方案B已经比方案A快了近一倍,少了一个Worktable,同样,page_index越大,扫描次数越多,因为子查询中要查询多余的(之前页)数据和字段,下面是查询第30页时的IO读取情况;

表 'ClassB'。扫描计数 1,逻辑读取 1241 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

方案C:双Top,取出截止到当前页为止的所有的ID,去掉之前页的ID,然后根据ID(通常是主键)作常规查询,性能最优;

DECLARE @page_size INT = 20;
DECLARE @page_index INT = 3;
WITH ID_List AS
(
SELECT TOP (@page_size * @page_index) ID FROM ClassB
WHERE CreateDate BETWEEN '2014-07-13' AND '2014-07-14'
ORDER BY CreateDate DESC, ID DESC
)
,ID_List_Current AS
(
SELECT ID FROM ID_List WHERE ID NOT IN(SELECT TOP (@page_size * (@page_index - 1)) ID FROM ID_List)
)
SELECT * FROM ClassB WHERE ID IN (SELECT ID FROM ID_List_Current);

表 'ClassB'。扫描计数 2,逻辑读取 52 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

查询第30页的数据仅比查询第3页的数据多出两次逻辑读取,方案C和B的唯一在于:子查询中的查询列,方案B中返回了所有字段,所有要通过聚集索引走lookup,而方案C直接返回索引键即可。

表 'ClassB'。扫描计数 2,逻辑读取 54 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

SQL Server 中的三种分页方式的更多相关文章

  1. SQL Server中的三种Join方式

      1.测试数据准备 参考:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek 这篇博客中的实验数据准备.这两篇博客使用了相同的实验数据. 2.SQ ...

  2. Asp.Net中的三种分页方式

    Asp.Net中的三种分页方式 通常分页有3种方法,分别是asp.net自带的数据显示空间如GridView等自带的分页,第三方分页控件如aspnetpager,存储过程分页等. 第一种:使用Grid ...

  3. 浅谈SQL Server中的三种物理连接操作

    简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...

  4. SQL Server中的三种物理连接操作

    来源:https://msdn.microsoft.com/zh-cn/library/dn144699.aspx 简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Out ...

  5. 浅谈SQL Server中的三种物理连接操作(HASH JOIN MERGE JOIN NESTED LOOP)

    简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...

  6. 浅谈SQL Server中的三种物理连接操作(Nested Loop Join、Merge Join、Hash Join)

    简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...

  7. Asp.Net中的三种分页方式总结

    本人ASP.net初学,网上找了一些分页的资料,看到这篇文章,没看到作者在名字,我转了你的文章,只为我可以用的时候方便查看,2010的文章了,不知道这技术是否过期. 以下才是正文 通常分页有3种方法, ...

  8. Sql Server 常见的几种分页方式

    ⒈offset fetch next方式[SqlServer2012及以上版本支持][推荐] select * from T_User order by id offset rows /*(页数-1) ...

  9. SQL Server中数据库文件的存放方式,文件和文件组

    原文地址:http://www.cnblogs.com/CareySon/archive/2011/12/26/2301597.html   SQL Server中数据库文件的存放方式,文件和文件组 ...

随机推荐

  1. 一个小应用的dbcp和c3p0配置实例

    以下是一个小应用的数据库连接池配置,包括DBCP和C3P0的配制方法 因为是小应用,完全不涉及访问压力,所以配置上采取尽量节约数据库资源的方式 具体要求如下:初始化连接数为0连接不够,需要新创建时,每 ...

  2. OpenCV码源笔记——RandomTrees (二)(Forest)

    源码细节: ● 训练函数 bool CvRTrees::train( const CvMat* _train_data, int _tflag,                        cons ...

  3. 如何写科技文章的讨论discussion部分

    众所周知,讨论部分是在结合自己的研究结果基础上,对整个文章的结论的提炼和升华.这一部分是整个论文的精,往往点睛作用. 同时,很多杂志要求结果和讨论分开,这也就更突出了写好讨论的重要性. 那么,我们应该 ...

  4. LA 6042 Bee Tower 记忆化搜索

    一开始读漏了很多细节,用递推写死活跑不出样例. 把题目中的细节列一下吧,状态方程很好推,改成记忆化搜索之后代码也很清晰. 1.蜜蜂需要到最高的塔去,最高的塔可能不止一个,抵达任意一个即可. 2.蜜蜂每 ...

  5. OGG-00782 - OGG 11.2.1.0.2 FOR Windows x64 Microsoft SQL Server

    OS ENV:主机名:           WIN-NO42QRNPMFAOS 名称:          Microsoft Windows Server 2008 R2 Datacenter OS ...

  6. Hadoop1.x与Hadoop2的区别

    转自:http://blog.csdn.net/fenglibing/article/details/32916445 六.Hadoop1.x与Hadoop2的区别 1.变更介绍 Hadoop2相比较 ...

  7. 高斯消元 分析 && 模板 (转载)

    转载自:http://hi.baidu.com/czyuan_acm/item/dce4e6f8a8c45f13d7ff8cda czyuan 先上模板: /* 用于求整数解得方程组. */ #inc ...

  8. 解析UML9种图的作用

    本文和大家重点讨论一下UML9种图的概念,UML中有五类图,共有9种图形,每种图形都有各自的特点,下面就让我们一起来看一下这些图形特点的详细介绍吧. UML9种图简介 1.用例图 说明的是谁要使用系统 ...

  9. Delphi反汇编内部字符串处理函数/过程不完全列表

    Delphi反汇编内部字符串处理函数/过程不完全列表 名称 参数 返回值 作用 等价形式 / 备注   _PStrCat EAX :目标字符串 EDX :源字符串 EAX 连接两个 Pascal 字符 ...

  10. I.MX6 Android U-blox miniPCI 4G porting

    /************************************************************************** * I.MX6 Android U-blox m ...