OFFSET FETCH 在 SQL Server 2022 中仍是标准分页语法,但仅适合浅层分页;深度分页性能断崖式下降,应改用键集分页(如 WHERE id > @last_seen_id)替代。

OFFSET FETCH 在 SQL Server 2022 里仍是标准分页语法,但“高性能”不来自它本身——它天生不适合深度分页。真要高性能,得绕开 OFFSET 大偏移,而不是优化它。
OFFSET FETCH 必须配 ORDER BY,否则直接报错
SQL Server 强制要求 ORDER BY 出现在 OFFSET 前面,且必须是查询的最终排序依据。漏写、写错顺序、或排序字段没出现在 SELECT 列表中(比如按 ISNULL(name, 'unknown') 排序但没选这个表达式),都会触发错误:
Msg 102, Level 15, State 1, Line X Incorrect syntax near 'OFFSET'.
- 视图或内联表值函数里用了
OFFSET,调用时没补ORDER BY→ 报错 - 用
SELECT *但ORDER BY依赖计算列(如LEN(email))→ 报错,除非显式 SELECT 该列 - 多层嵌套查询中,
OFFSET必须在最外层,且紧贴ORDER BY结尾
分页参数计算别写错:OFFSET = (@page - 1) * @page_size
前端传的是页码 @page(通常从 1 开始)和每页条数 @page_size,SQL 层必须转成偏移量。常见错误是把 @page * @page_size 当 OFFSET,导致跳过重复数据或漏行:
- 第 1 页 →
OFFSET 0 ROWS - 第 3 页,每页 20 条 →
OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY(不是 60) -
FETCH NEXT后面必须带ONLY,缺字会语法错误 - 变量建议用
INT,避免隐式转换;若@page可能为 0,需提前校验,否则OFFSET -20 ROWS直接失败
OFFSET 超过 1 万行时,性能断崖式下跌
SQL Server 不会“跳索引”,而是扫描并丢弃前 N 行。哪怕 ORDER BY id 有聚集索引,OFFSET 100000 ROWS 仍要逻辑读至少 10 万 + @page_size 行。实测响应时间可能从 20ms 升到 2s+。
- 执行计划里看「实际行数」,如果远大于
FETCH NEXT数值,说明已中招 - 加索引没用——索引只能加速定位起点,无法跳过中间行
- 替代方案不是调优
OFFSET,而是换键集分页:WHERE id > @last_seen_id ORDER BY id OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY - 键集分页要求排序字段唯一且单调(如自增
id或带时钟的created_at),否则可能漏/重数据
真正卡住性能的不是语法写错,而是误以为 OFFSET 是“高效原语”。它简洁、标准、易读,但仅适合页码靠前的场景。一旦用户拖到第 500 页,问题不在怎么写,而在该不该用它。


















