SQL Server 2012 OFFSET/FETCH NEXT分页示例

本文介绍SQL Server 2005及以后版本中的两种分页方法:使用ROW_NUMBER()函数和SQL Server 2012新增的OFFSET FETCH NEXT子句。通过示例对比这两种方法,并分析它们在性能上的差异。

原文:http://beyondrelational.com/modules/29/presentations/483/scripts/12983/sql-server-2012-server-side-paging-demo-using-offsetfetch-next.aspx?utm_source=brnewsletter&utm_medium=email&utm_campaign=2012Apr

SQL Server 2005 引入了 ROW_NUMBER()来提供一种容易的分页方式。
SQL Server 2012 添加了另外一种更简单高效的分页方式。


/*
执行脚本去创建这个表并插入数据。
*/
IF OBJECT_ID('Customers','U') IS NOT NULL
    DROP TABLE Customers
 
CREATE TABLE Customers (
    CustomerID INT,
    CustomerNumber CHAR(4),
    CustomerName VARCHAR(50),
    CustomerCity VARCHAR(20) )
GO
 
INSERT INTO Customers (
    CustomerID, CustomerNumber, CustomerName, CustomerCity
)
SELECT
    Number,
    REPLACE(STR(Number, 4), ' ', '0'),
    'Customer ' + STR(number,6),
    CHAR(65 + (number % 26)) + '-City'
FROM master..spt_values WHERE type = 'p'
    AND number BETWEEN 0 AND 999
 
/*
用ROW_NUMBER()的分页示例- SQL Server 2005/2008 版本。
*/
 
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
 
/*
SQL Server 2012中新添加的分页示例
*/
 
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;
 
/*
同时执行这两个版本,打开执行计划,你可以注意到在这个例子中显著的性能差异。
*/





<think> 首先,用户的问题是:“我想了解SQL Server中TOP和OFFSET FETCH的区别 请问SQL Server中TOP和OFFSET FETCH的区别”。用户明确询问SQL Server中TOP和OFFSET FETCH的区别。 从系统指令中,我有几个关键点: - 所有行内数学表达式必须使用$...$格式。 - 独立公式必须使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户提到了“参考站内引用”,并提供了引用[1]到[4]。这些引用是关于OFFSET..FETCH、LIMIT..OFFSET、TOP等的讨论。我需要参考这些引用来回答用户的问题。 回顾引用内容: - 引用[1]:提到OFFSET..FETCH是语法变体,其他变体包括MySQL和PostgreSQL的LIMIT..OFFSETSQL Server和Sybase的TOP..START AT。 - 引用[2]:指出OFFSET-FETCH比TOP更灵活,支持跳过功能,但TOP支持PERCENT和WITH TIES选项,而OFFSET-FETCH不支持。建议使用OFFSET-FETCH作为默认,除非需要TOP特有的功能。 - 引用[3]:强调排序运算在SQL中是最后执行的,ORDER BY和OFFSETFETCH是保证顺序的有效方式。 - 引用[4]:是关于SQL分组后根据最大值得到记录明细的示例查询,使用ROW_NUMBER() OVER()。 我的回答需要基于这些引用,但用户说“上述引用仅供参考,并不是用户真正的需求”,所以我应该优先参考用户的问题和我的回答历史。用户的问题是新的,所以我直接回答这个查询。 用户的问题焦点是TOP和OFFSET FETCHSQL Server中的区别。 关键区别: - TOP子句:用于限制返回的行数,但不支持跳过行。语法是TOP n [PERCENT] [WITH TIES]。 - OFFSET FETCH子句:用于分页,支持跳过行(OFFSET)和取行(FETCH)。语法是OFFSET n ROWS FETCH NEXT m ROWS ONLY。 区别总结: 1. 灵活性: - TOP只能指定返回的行数,不能跳过行。 - OFFSET FETCH可以跳过行(OFFSET)然后再取行(FETCH),适合分页。 2. 选项: - TOP支持PERCENT(返回百分比的行)和WITH TIES(包括平局的最后一行的额外行)。 - OFFSET FETCH不支持PERCENT或WITH TIES。 3. 标准化: - OFFSET FETCH是ANSI SQL标准的一部分。 - TOP是SQL Server特有的语法。 4. 使用场景: - TOP适用于简单限制行数,比如取前10条记录。 - OFFSET FETCH适用于分页查询,比如跳过前10条取接下来的10条。 从引用[2]:OFFSET-FETCH支持跳过功能,但TOP不支持;TOP支持PERCENT和WITH TIES,OFFSET-FETCH不支持。建议使用OFFSET-FETCH作为默认。 从引用[3]:ORDER BY和OFFSETFETCH是排序和分页的有效方式。 回答结构: - 先简要介绍TOP和OFFSET FETCH。 - 然后详细比较区别。 - 给出示例代码(SQL查询)。 - 使用中文。 - 生成相关问题。 - 在回答中引用段落末尾添加引用标识。引用来自给定的引用[1]-[4],所以我应该在相关部分引用它们。 例如,当提到OFFSET FETCH的灵活性时,可以引用[2]。 确保LaTeX使用正确:用户的问题中没有数学表达式,但如果有的话,比如示例查询,我需要处理。SQL查询不是数学表达式,所以我可以用代码块表示。 指令说“所有行内数学表达式必须使用$...$格式”,但SQL代码不是数学表达式,所以不需要。我会用代码块来表示SQL查询。 响应格式: - 清晰的结构。 - 使用标题或段落。 生成相关问题:在最后添加相关问题部分。 相关问题想法: 1. 如何在SQL Server中实现高效分页? 2. TOP子句的WITH TIES选项是如何工作的? 3. OFFSET FETCH的性能考虑是什么? 4. 在什么情况下应该使用TOP而不是OFFSET FETCH? 现在,构建回答。 </think> ### SQL Server中TOP和OFFSET FETCH的区别 在SQL Server中,`TOP`和`OFFSET FETCH`都是用于限制查询结果集行数的子句,但它们在功能、灵活性和标准化方面有显著差异。下面我将从多个维度逐步解释它们的区别,并结合示例代码和引用内容进行说明。 #### 1. **基本功能与语法** - **TOP子句**: - `TOP`用于指定返回的前N行记录,但不能跳过任何行。 - 语法:`SELECT TOP n [PERCENT] [WITH TIES] columns FROM table [ORDER BY ...]` - 示例:查询前5条员工记录。 ```sql SELECT TOP 5 * FROM Employees ORDER BY HireDate; ``` - 特点:`TOP`支持`PERCENT`选项(返回百分比的行,如`TOP 10 PERCENT`)和`WITH TIES`选项(当ORDER BY有平局时,返回额外的行),但它无法实现跳过行(如分页中的“偏移”)。 - **OFFSET FETCH子句**: - `OFFSET FETCH`用于分页查询,支持跳过行(OFFSET)后取行(FETCH)。 - 语法:`SELECT columns FROM table ORDER BY ... OFFSET n ROWS FETCH NEXT m ROWS ONLY` - 示例:跳过前5条记录后取接下来的5条记录(实现第二页数据)。 ```sql SELECT * FROM Employees ORDER BY HireDate OFFSET 5 ROWS FETCH NEXT 5 ROWS ONLY; ``` - 特点:它专为分页设计,无法使用`PERCENT`或`WITH TIES`选项,但能灵活处理行偏移。 引用[2]强调了OFFSET-FETCH的灵活性:“OFFSET-FETCH子句比TOP子句更灵活,因为它支持跳过功能”,这对于分页场景至关重要[^2]。 #### 2. **关键区别对比** 下表总结了`TOP`和`OFFSET FETCH`的主要区别: | 维度 | TOP子句 | OFFSET FETCH子句 | |--------------------|----------------------------------|--------------------------------| | **跳过行支持** | 不支持(只能取前N行) | 支持(通过OFFSET跳过行) | | **PERCENT选项** | 支持(如`TOP 10 PERCENT`) | 不支持 | | **WITH TIES选项** | 支持(返回ORDER BY平局的额外行) | 不支持 | | **标准化程度** | SQL Server特有语法(非标准) | ANSI SQL标准语法(更通用) | | **主要使用场景** | 简单限制行数(如取Top N记录) | 分页查询(如跳过M行取N行) | | **性能考虑** | 通常高效,但大数据集分页时可能差 | 分页更优,但OFFSET大时性能下降 | - **灵活性**:`OFFSET FETCH`支持分页跳行,这在TOP中无法实现。引用[2]指出:“如你所见,从支持跳过功能看,OFFSET-FETCH子句比TOP子句更灵活”[^2]。 - **选项支持**:`TOP`独有的`WITH TIES`和`PERCENT`选项使其在某些场景更强大,例如返回销售排名前10%的记录(包括平局行)。而`OFFSET FETCH`缺少这些功能。 - **标准化优势**:`OFFSET FETCH`是ANSI SQL标准的一部分,而`TOP`是SQL Server特有语法。引用[1]提到OFFSET..FETCH是“唯一的语法变体”,与其他数据库如MySQL的LIMIT..OFFSET类似,这提高了跨数据库兼容性[^1]。 - **性能方面**:对于分页,`OFFSET FETCH`更高效,尤其当结合ORDER BY时;但OFFSET值大时可能需要优化(如使用键值分页)。`TOP`在简单查询中更快,但分页场景需额外逻辑(如嵌套查询)。 #### 3. **使用场景与示例** - **何时使用TOP**: - 需要快速获取前N条记录,且不需要跳过行。 - 示例:查询最新添加的3个产品(包括平局)。 ```sql SELECT TOP 3 WITH TIES * FROM Products ORDER BY CreateDate; ``` - 这里`WITH TIES`确保如果有日期相同的产品,额外行也会返回。 - **何时使用OFFSET FETCH**: - 实现分页,如Web应用中的“下一页”功能。 - 示例分页查询订单记录(第2页,每页10行)。 ```sql SELECT * FROM Orders ORDER BY OrderDate DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY; ``` 引用[3]强调排序的重要性:“排序运算不仅在 SQL 语句的最后,而且是最后执行的。使用 ORDER BY 和 OFFSETFETCH 是保证数据顺序的最有效方式”[^3]。 - **结合使用场景**:两者可嵌套使用,例如先取Top N再分页,但这可能增加复杂性。 #### 4. **建议与最佳实践** - **默认选择**:大多数情况下,优先使用`OFFSET FETCH`,尤其当需要分页或跨数据库兼容时。引用[2]建议:“由于OFFSET-FETCH是标准的,而TOP不是,我建议使用OFFSET-FETCH作为你的默认选择,除非你需要TOP支持且OFFSET-FETCH不支持的功能”[^2]。 - **性能优化**:对于大数据集,避免大OFFSET值(FETCH NEXT);考虑使用ROW_NUMBER()(如引用[4]的示例)或键值分页(如WHERE子句过滤)。 - 引用[4]展示了ROW_NUMBER()用法:“分组后根据最大值得到记录明细”[^4],这可用于高效分页: ```sql SELECT * FROM ( SELECT ROW_NUMBER() OVER(ORDER BY HireDate) AS RowNum, * FROM Employees ) AS T WHERE RowNum BETWEEN 6 AND 10; ``` - **注意事项**:两者都依赖于ORDER BY子句;否则,结果顺序不确定。引用[3]提醒:“其他排序方式有随机性”[^3]。 通过以上分析,核心区别在于:`TOP`适合简单行限制,而`OFFSET FETCH`专为分页设计,更灵活且标准化。实际选择取决于具体需求(如是否需要跳过行或特定选项)。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值