SQLServer · 最佳实践 · SQL Server 2012 使用OFFSET分页遇到的问题
1. 背景
最近有一个客户遇到一个奇怪的问题,以前使用ROW_NUMBER来分页结果是正确的,但是替换为SQL SERVER 2012的OFFSET...FETCH NEXT来分页出现了问题,因此,这里简单分析一下原因,更深层次的原因还没有确切的结论,但可以提供解决办法。 在升级数据库后并且应用新功能时,这个问题可能会困扰一些同学。
2. 现象
为了复现在这个问题 ,我们使用SQL SERVER 2012的示例库AdventureWorks2012,因为只复现功能问题,其他性能问题忽略,只需要能够正常运行就好了。我们以Sales.SalesOrderHeader为例。
最开始语句是这样的:
USE AdventureWorks2012
GO
WITH OrderedOrders AS
(
SELECT SalesOrderID, OrderDate,DueDate,
ROW_NUMBER() OVER (ORDER BY OrderDate ) AS RowNumber
FROM Sales.SalesOrderHeader
)
SELECT SalesOrderID, OrderDate,DueDate
FROM OrderedOrders
WHERE RowNumber BETWEEN 50 AND 60;
运行的结果是这样的:
在SQL SERVER 2012上是这样的:
USE AdventureWorks2012
GO
SELECT
SalesOrderID, OrderDate,DueDate
FROM Sales.SalesOrderHeader
ORDER BY OrderDate
OFFSET 49 ROWS FETCH NEXT 11 ROWS ONLY
运行的结果是这样的:
3. 分析与解决
好,我们来看看,因为表数据少,我们看看整个表的数据库 ,从50到60条数据的值
SELECT
SalesOrderID, OrderDate,DueDate
FROM Sales.SalesOrderHeader
这里可以看出来, 业务想要的数据和ROW_NUMBER分页产生的数据是一致的,也就是正确的数据。但是与OFFSET来分页的做对比,就出现问题了。
我们可以看到OrderDate = 2005-07-03 00:00:00.000的有5条数据,取了前3天,后2条丢弃了,正常是取后3条。这个地方发生了什么? 我们可以看看实际执行计划。
ROW_NUMBER:
这个地方的物理操作和逻辑操作都是Sort。
而用OFFSET的实际执行计划:
这个地方的物理操作是Sort,但逻辑操作都是TOP N Sort。
而我最初以为由于Sort和TOP N Sort的导致的,我们再看看他们的准确定义:
Sort:Sort 运算符可对所有传入的行进行排序。Argument 列包含 DISTINCT ORDER BY:()谓词(如果此操作删除重复项)或 ORDER BY:()谓词(如果对逗号分隔的列列表进行排序)
TOP N Sort:Top N Sort 与 Sort 迭代器类似,差别仅在于前者需要前 N 行,而不是整个结果集。如果 N 的值较小,SQL Server 查询执行引擎将尝试在内存中执行整个排序操作。如果 N 的值较大,查询执行引擎将使用更通用的排序方法(该方法不采用 N 作为参数)重新排序。
其实看得出来,似乎关系不大,但也可能是这个原因导致。为何OFFSET方式只随机取了OrderDate的某个值其中的一些?,这个准确原因也不是很清楚,至少我现在为看到有这类解释,或许TOP N SORT的算法本省就是这样,这个留在后面再调查一下。
而实际上,微软的帮助文档说得很清楚,要实现结果的唯一性或者持久一致性,必须满足下列条件:
1. 查询使用的基础数据不能发生变化
2. ORDER BY 子句包含保证是唯一的列或列组合
嗯,确实这个说法没错,如果更将主键列加入ORDER BY ,确实可以解决:
USE AdventureWorks2012
GO
SELECT
SalesOrderID, OrderDate,DueDate
FROM Sales.SalesOrderHeader
ORDER BY SalesOrderID,OrderDate
OFFSET 49 ROWS FETCH NEXT 11 ROWS ONLY
这时候,实际的执行计划其实已经发生改变:
SORT操作不再需要,因为通过cluster index san取出来的数据已经是排序过了(ORDERED为1)。
我们还可以看到,OrderDate上是没有INDEX的,如果我们加上IDNEX,会是怎么样呢?
CREATE INDEX IX_SalesOrderHeader_OrderDate
ON Sales.SalesOrderHeader(OrderDate)
WITH(ONLINE=ON)
然后,我们再看看执行计划 :
很明显,也是没有问题的。
4. 最佳实践
遇到这类问题,提供两个建议:
1. ORDER BY 子句包含保证是唯一的列或列组合
2. ORDER BY 子句的列或列组合可以利用INDEX进行排序(实际的执行计划必须是排序过的操作)
SQLServer · 最佳实践 · SQL Server 2012 使用OFFSET分页遇到的问题的更多相关文章
- Sql Server 2012 的新分页方法分析(offset and fetch) - 转载
最近在分析 Sql Server 2012 中 offset and fetch 的新特性,发现 offset and fetch 无论语法的简洁还是功能的强大,都是相当相当不错的 其中 offset ...
- SQL Server 2012使用Offset/Fetch Next实现分页
在Sql Server 2012之前,实现分页主要是使用ROW_NUMBER(),在SQL Server2012,可以使用Offset ...Rows Fetch Next ... Rows onl ...
- SQL Server 2012使用OFFSET/FETCH NEXT分页及性能测试
最近在网上看到不少文章介绍使用SQL Server 2012的新特性:OFFSET/FETCH NEXT 实现分页.多数文章都是引用或者翻译的这一篇<SQL Server 2012 - Serv ...
- SQL Server 2012 新的分页函数 OFFSET & FETCH NEXT
DECLARE @page INT, @size INT;select @page = 300, @size = 10 SELECT *FROM gpcomp1.GPCUSTWHERE company ...
- SQL Server 2012提供的OFFSET/FETCH NEXT与Row_Number()对比测试(转)
原文地址:http://www.cnblogs.com/downmoon/archive/2012/04/19/2456451.html 在<SQL Server 2012服务端使用OFFSET ...
- SQL Server 2012提供的OFFSET/FETCH NEXT与Row_Number()对比测试 [T]
SQL Server 2008中SQL应用系列--目录索引 前些天看到一篇文章<SQL Server 2012 - Server side paging demo using OFFSET/FE ...
- Sql Server 2012 分页方法分析(offset and fetch)
最近在分析 Sql Server 2012 中 offset and fetch 的新特性,发现 offset and fetch 无论语法的简洁还是功能的强大,都是相当相当不错的.其中 offse ...
- SQLServer · 最佳实践 · 如何将SQL Server 2012降级到2008 R2-博客-云栖社区-阿里云
迁移须知 使用SQLSERVER 2012的特性在SQL 2008 R2不支持,比如新的分页方式 此迁移操作手册适用于MSSQL2012到MSSQL2008R2的迁移 迁移使用微软提供的脚本生成和导入 ...
- SQL Server 2012 OFFSET/FETCH NEXT分页示例(转载)
原文:http://beyondrelational.com/modules/29/presentations/483/scripts/12983/sql-server-2012-server-sid ...
随机推荐
- 贪吃蛇小游戏—C++、Opencv编写实现
贪吃蛇游戏,C++.Opencv实现 设计思路: 1.显示初始画面,蛇头box初始位置为中心,食物box位置随机 2.按随机方向移动蛇头,按a.s.d.w键控制移动方向,分别为向左,向下,向右,向上 ...
- I.MX6 AW-NB177NF p2p support
/***************************************************************************** * I.MX6 AW-NB177NF p2 ...
- 【Codeforces 757B】 Bash's big day
[题目链接] 点击打开链接 [算法] 若gcd(s1,s2,s3....sk) > 1, 则说明 : 一定存在一个整数d满足d|s1,d|s2,d|s3....,d|sk 因为我们要使|s|尽可 ...
- bzoj 2836 魔法树 —— 树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2836 树链剖分裸题: 写码五分钟,调码两小时,RE不断,狂交二十五遍,终于找到一处小细节—— ...
- mysql负载均衡方案
mysql负载均衡方案 一.直接连接 数据库的读写分离方案很多,这里介绍基于mysql数据库的读写分离方案. 比较常见的读写分离方案如下: 1 基于查询分离 最简单的分离方法是将读和写分发到主和从服务 ...
- Python-day-9- RabbitMQ队列
RabbitMQ队列 安装 http://www.rabbitmq.com/install-standalone-mac.html 安装python rabbitMQ module pip insta ...
- 1-1 课程导学 & 1-2 项目需求分析,技术分解.
1-1 课程导学 1-2 项目需求分析,技术分解. 要有一定的dart基础,了解安卓和ios的一些普通的开发
- 腾讯QQ团队开源分布式后台毫秒服务引擎全解析:引擎架构、RPC、灰度……
腾讯QQ团队将于12月4日开源一个服务开发运营框架,叫做毫秒服务引擎(Mass Service Engine in Cluster,MSEC),它集RPC.名字发现服务.负载均衡.业务监控.灰度发布. ...
- Centos 内存释放
原因:最近发现服务器老师提示内存不足的警报,很多时候内存都占用百分之80以上,查看运行的服务似乎并没有占用很大的内存,top查看运行的服务,然后按shift+m排名第一的才百分之1.x,看了别人的博客 ...
- python之类的相关名词-继承-
继承:父类有的功能,子类继承后也都有 继承是直接把父类方法写入子类的object里 如果定义的类有很多重复的功能,可以把重复的类定义成父类 静态方法:不需要实例化就可以调用,不可以调用类里面的变量和方 ...