SQL Server 2012提供的OFFSET/FETCH NEXT与Row_Number()对比测试

本文对比了SQLServer2012中OFFSET/FETCHNEXT与SQLServer2005/2008中Row_Number()进行分页的效果。通过测试发现,新的分页方法在逻辑读取数、响应时间和实际执行行数等方面都有显著提升。

SQL Server 2008中SQL应用系列--目录索引

前些天看到一篇文章《SQL Server 2012 - Server side paging demo using OFFSET/FETCH NEXT》,原文地址。作者在文中称,要SQL Server 2012使用OFFSET/FETCH NEXT分页,比SQL Server 2005/2008中的RowNumber()有显著改进。今天特地作了简单测试。现将过程分享如下:

附:我的测试环境为:
SQL Server 2012,命名实例

Microsoft SQL Server 2012 - 11.0.2100.60 (Intel X86)
Feb 10 2012 19:13:17
Copyright (c) Microsoft Corporation
Enterprise Edition on Windows NT 6.0 <X86> (Build 6002: Service Pack 2)

沿用上文的测试数据库和表:

IF OBJECT_ID('DemoPager2012') IS NOT NULL
DROP DataBase DemoPager2012
GO

CREATE Database DemoPager2012
GO

USE DemoPager2012
GO/*
Setup script to create the sample table and fill it with
sample data.
*/
IF OBJECT_ID('Customers','U') IS NOT NULL
DROP TABLE Customers

CREATE TABLE Customers ( CustomerID INT primary key identity(1,1),
CustomerNumber CHAR(4),
CustomerName VARCHAR(50),
CustomerCity VARCHAR(20) )
GOTRUNCATE table Customers
GO

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

/*****运用CTE递归插入,速度较快,邀月注***********************/
WITH Seq (num,CustomerNumber, CustomerName, CustomerCity) AS
(SELECT 1,cast('0000'as CHAR(4)),cast('Customer 0' AS NVARCHAR(50)),cast('X-City' as NVARCHAR(20))
UNION ALL
SELECT num + 1,Cast(REPLACE(STR(num, 4), ' ', '0') AS CHAR(4)),
cast('Customer ' + STR(num,6) AS NVARCHAR(50)),
cast(CHAR(65 + (num % 26)) + '-City' AS NVARCHAR(20))
FROM Seq
WHERE num <= 10000
)
INSERT INTO Customers (CustomerNumber, CustomerName, CustomerCity)
SELECT CustomerNumber, CustomerName, CustomerCity
FROM Seq
OPTION (MAXRECURSION 0)

插入1万条数据后,在SQL Server 2008 R2中执行Row_Number():
/*
Server side paging demo using ROW_NUMBER() - SQL Server
2005/2008 version.
*/

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO


DECLARE @page INT, @size INT
SELECT @page = 3, @size = 10

;WITH cte AS (
SELECT TOP (@page * @size)
CustomerID,
CustomerName,
CustomerCity,
ROW_NUMBER() OVER(ORDER BY CustomerName ) AS Seq,
COUNT(*) OVER(PARTITION BY '') AS Total
FROM Customers
WHERE CustomerCity IN ('A-City','B-City')
ORDER BY CustomerName ASC
)
SELECT * FROM cte
WHERE seq BETWEEN (@page - 1 ) * @size + 1 AND @page * @size
ORDER BY seq;
GO

SET STATISTICS IO OFF ;
SET STATISTICS TIME OFF;
GO

SQL Server 2012中执行OFFSET/FETCH NEXT语句如下:

/*
Server side paging demo using the new enhancements added
in SQL Server 2012
*/
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO


DECLARE @page INT, @size INT
SELECT @page = 3, @size = 10

SELECT
*,
COUNT(*) OVER(PARTITION BY '') AS Total
FROM Customers
WHERE CustomerCity IN ('A-City','B-City')
ORDER BY CustomerID
OFFSET (@page -1) * @size ROWS
FETCH NEXT @size ROWS ONLY;
GO

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
GO


在SQL Server 2012中执行如下语句:

DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO

DECLARE @page INT, @size INT
SELECT @page = 3, @size = 10

;WITH cte AS (
SELECT TOP (@page * @size)
CustomerID,
CustomerName,
CustomerCity,
ROW_NUMBER() OVER(ORDER BY CustomerName ) AS Seq,
COUNT(*) OVER(PARTITION BY '') AS Total
FROM Customers
WHERE CustomerCity IN ('A-City','B-City')
ORDER BY CustomerName ASC
)
SELECT * FROM cte
WHERE seq BETWEEN (@page - 1 ) * @size + 1 AND @page * @size
ORDER BY seq;


SELECT
*,
COUNT(*) OVER(PARTITION BY '') AS Total
FROM Customers
WHERE CustomerCity IN ('A-City','B-City')
ORDER BY CustomerID
OFFSET (@page -1) * @size ROWS
FETCH NEXT @size ROWS ONLY;
GO

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
GO


结论:无论是从逻辑读取数还是响应时间实际执行行数等关键参数看,SQL Server 2012提供的OFFSET/FETCH NEXT分页方式都比Row_Number()方式有了较大的提升。


邀月注:本文版权由邀月和优快云共同所有,转载请注明出处。
助人等于自助! 3w@live.cn



SQL Server 中`ROW_NUMBER() OVER()`是一个窗口函数,用于为查询结果集中的每一行分配一个唯一的行号。 ### 语法 `ROW_NUMBER() OVER(partition by 分组列 order by 排序列)` [^1]。其中,`partition by` 子句可选,用于将结果集划分为多个分区;`order by` 子句必选,用于指定每个分区内的排序方式 [^1][^2][^3]。 ### 功能 - **分组排序**:该函数可以对数据进行分组,并在每个分组内进行排序,为每个分组内的行分配一个唯一的行号 [^1][^2][^3]。 - **分页**:可以结合`ROW_NUMBER()`实现分页功能,通过筛选指定范围的行号来获取指定页的数据 [^5]。 ### 应用场景 - **排名**:为数据集中的每一行分配一个排名,如按成绩、销售额等进行排名 [^1][^3]。 - **分页查询**:在处理大量数据时,将数据分页显示,提高查询效率 [^5]。 - **筛选每组的前几条记录**:通过`ROW_NUMBER()`为每组数据编号,然后筛选出每组编号小于等于指定值的记录。 ### 示例 #### 仅对数据进行排序 按照 C# 分数从高到低进行排名: ```sql select *,ROW_NUMBER() over(order by CSharp desc) as CSharpRank from ScoreList ``` #### 分组排序 从表中查找雇员 ID、所属部门、薪水以及薪水在部门中的名次: ```sql select employeeId, departmentId, salary, row_number() over(partition by departmentId order by salary desc) rank from table ``` #### 分页查询 ```sql SELECT p.id, p.accieptname, p.addtime FROM [dbo].[GongCaiOrder_a] p order by addtime OFFSET (pageindex - 1) * pagesize rows fetch next pagesize rows only ``` ### 注意事项 在使用`ROW_NUMBER() OVER()`函数时,`OVER()`里面的分组以及排序的执行晚于`WHERE`、`GROUP BY`、`ORDER BY`的执行 [^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值