SQL Server 中的三种分页方式
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 中的三种分页方式的更多相关文章
- SQL Server中的三种Join方式
1.测试数据准备 参考:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek 这篇博客中的实验数据准备.这两篇博客使用了相同的实验数据. 2.SQ ...
- Asp.Net中的三种分页方式
Asp.Net中的三种分页方式 通常分页有3种方法,分别是asp.net自带的数据显示空间如GridView等自带的分页,第三方分页控件如aspnetpager,存储过程分页等. 第一种:使用Grid ...
- 浅谈SQL Server中的三种物理连接操作
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- SQL Server中的三种物理连接操作
来源:https://msdn.microsoft.com/zh-cn/library/dn144699.aspx 简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Out ...
- 浅谈SQL Server中的三种物理连接操作(HASH JOIN MERGE JOIN NESTED LOOP)
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- 浅谈SQL Server中的三种物理连接操作(Nested Loop Join、Merge Join、Hash Join)
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- Asp.Net中的三种分页方式总结
本人ASP.net初学,网上找了一些分页的资料,看到这篇文章,没看到作者在名字,我转了你的文章,只为我可以用的时候方便查看,2010的文章了,不知道这技术是否过期. 以下才是正文 通常分页有3种方法, ...
- Sql Server 常见的几种分页方式
⒈offset fetch next方式[SqlServer2012及以上版本支持][推荐] select * from T_User order by id offset rows /*(页数-1) ...
- SQL Server中数据库文件的存放方式,文件和文件组
原文地址:http://www.cnblogs.com/CareySon/archive/2011/12/26/2301597.html SQL Server中数据库文件的存放方式,文件和文件组 ...
随机推荐
- Quartz所使用的表的说明
Quartz将Job保存在数据库中所需表的说明 QRTZ_CALENDARS 以 Blob 类型存储 Quartz 的 Calendar 信息 QRTZ_CRON_TRIGGERS 存储 Cron T ...
- 1401 - Remember the Word
注意到单词的长度最长100,其实最糟糕复杂度应该能到O(300005*100),需要注意的是在字典树上匹配单词时,一旦不匹配,则后面的就不会匹配,需要break出来(这个害我TLE查了半天,日!),还 ...
- linq 分类
linq技术为我们开发人员提供了五个比较实用的数据访问类型: LinQ to Object:可以允许对内存中的类对象查询. LinQ to DataSet:可以对内存中的DataSet缓存数据,执行数 ...
- [原创]使用命令行工具提升cocos2d-x开发效率(一)之TexturePacker篇
TexturePacker是一个常用的制作sprite sheet的工具,它提供了很多实用的功能. 一般我们制作sprite sheet都是使用他的gui版本,纯手工操作,就像下面这张图示的一样. 刚 ...
- PHP之APC缓存详细介绍(转)
1.APC缓存简介 APC,全称是Alternative PHP Cache,官方翻译叫”可选PHP缓存”.它为我们提供了缓存和优化PHP的中间代码的框架. APC的缓存分两部分:系统缓存和用户数据缓 ...
- ios开发之 MPMoviePlayerController 视频播放器
MPMoviePlayerController 与AVAudioPlayer有点类似,前者播放视频,后者播放音频,不过也有很大不同,MPMoviePlayerController 可以直接通过远程UR ...
- kail新手安装
Kali Linux下载链接:http://mirrors.ustc.edu.cn/kali-images/kali-2.0/ (ps:建议用国内镜像源下载,速度有保证) Kali Linux安装之后 ...
- git文件未改动pull的时候提示冲突
今天在mac下使用git工具,出现一个很奇怪的问题. 先声明当前工作目录是干净的,运行 git status 没有任何文件改动,且没有任何需要push的文件. 我执行 git pull 命令,直接提示 ...
- hdu 4901 The Romantic Hero (dp)
题目链接 题意:给一个数组a,从中选择一些元素,构成两个数组s, t,使s数组里的所有元素异或 等于 t数组里的所有元素 位于,求有多少种构成方式.要求s数组里 的所有的元素的下标 小于 t数组里的所 ...
- BZOJ_1029_[JSOI2007]_建筑抢修_(贪心+优先队列)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1029 \(n\)个任务需要完成,给出每个任务所需时间\(t_1\)与deadline\(t_2 ...