在SQL Server的数据库开发中,翻页查询是处理大量数据展示的核心需求之一,当数据表记录数达到上万甚至百万级别时,一次性返回所有数据会导致查询缓慢、内存占用过高,因此需要通过翻页只返回当前页需要的数据。

传统翻页方式:TOP加子查询
早期SQL Server版本中,最常用的翻页方式是结合TOP和子查询实现,核心思路是先查询出前N页的所有数据,再从中取最后页的数据。假设我们有一张用户表user_info,结构如下:
-- 用户表结构示例
CREATE TABLE user_info (
id INT PRIMARY KEY IDENTITY(1,1),
user_name NVARCHAR(50) NOT NULL,
age INT,
create_time DATETIME DEFAULT GETDATE()
)
如果要查询第3页,每页10条数据,使用传统方式的SQL如下:
-- 查询第3页,每页10条,按id升序排序
SELECT TOP 10 *
FROM user_info
WHERE id NOT IN (
SELECT TOP 20 id -- 跳过前2页共20条数据
FROM user_info
ORDER BY id ASC
)
ORDER BY id ASC
这种方式的缺点是当页数较大时,子查询需要扫描的数据量会成倍增加,比如查询第1000页时,子查询需要取前9990条数据的id,性能会明显下降,而且如果排序字段有重复值,还可能出现数据重复的问题。
ROW_NUMBER函数翻页
SQL Server 2005及以后版本引入了ROW_NUMBER()窗口函数,可以更稳定地实现翻页,它可以为每一行数据生成一个唯一的行号,通过行号筛选对应页的数据。同样查询第3页每页10条数据的SQL如下:
-- 使用ROW_NUMBER实现翻页
WITH user_rank AS (
SELECT *,
ROW_NUMBER() OVER (ORDER BY id ASC) AS row_num -- 按id升序生成行号
FROM user_info
)
SELECT *
FROM user_rank
WHERE row_num BETWEEN 21 AND 30 -- 第3页的行号范围是21到30
这种方式比传统TOP子查询更稳定,不会出现重复数据的问题,但是在数据量较大时,生成所有行的行号依然会有一定的性能开销,尤其是排序字段没有索引的时候,会触发全表排序。
OFFSET FETCH翻页(推荐)
SQL Server 2012及以后版本官方推荐使用的翻页语法是OFFSET FETCH,它是ORDER BY子句的扩展,语法更简洁,性能也更优。同样查询第3页每页10条数据的SQL如下:
-- 使用OFFSET FETCH实现翻页 SELECT * FROM user_info ORDER BY id ASC OFFSET 20 ROWS -- 跳过前20条数据(前2页) FETCH NEXT 10 ROWS ONLY -- 取接下来的10条数据
这种语法的优势非常明显,首先语法简洁易懂,不需要写子查询或者公用表表达式,其次SQL Server会对这种语法做专门的优化,在数据量较大时性能比前两种方式更好。需要注意的是,使用OFFSET FETCH必须搭配ORDER BY子句,否则会报错。
翻页性能优化建议
无论使用哪种翻页方式,想要提升查询性能,都需要做好以下几点优化:
- 翻页的排序字段尽量使用有索引的字段,尤其是主键或者唯一索引字段,避免全表扫描和排序。
- 只查询需要的字段,不要使用
SELECT *,减少数据传输和内存占用。 - 如果业务场景允许,尽量使用基于主键的翻页,比如记录上一页最后一条数据的主键id,下次查询时直接从这个id之后开始取,性能会比通用翻页更好。
基于主键的翻页示例:假设上一页最后一条数据的id是20,查询下一页10条数据:
-- 基于主键的翻页,性能最优 SELECT TOP 10 * FROM user_info WHERE id > 20 -- 从上次最后一条数据的id之后开始查 ORDER BY id ASC
不同翻页方式对比
以下是三种常见翻页方式的对比:
| 翻页方式 | 适用版本 | 性能表现 | 语法复杂度 |
|---|---|---|---|
| TOP加子查询 | 所有SQL Server版本 | 数据量大时较差 | 较高 |
| ROW_NUMBER函数 | SQL Server 2005及以上 | 中等 | 中等 |
| OFFSET FETCH | SQL Server 2012及以上 | 较优 | 低 |
实际开发中,建议优先使用OFFSET FETCH方式实现翻页,如果使用的SQL Server版本低于2012,可以选择ROW_NUMBER函数的方式,尽量避免使用传统的TOP子查询翻页方式。
SQL_Server翻页查询OFFSET_FETCHROW_NUMBER性能优化修改时间:2026-07-02 19:33:37