OFFSET FETCH 是 SQL Server 2012+ 唯一原生支持的“跳过-取回”分页语法,必须配合 ORDER BY 使用,否则报错;第 n 页需计算为 OFFSET (@page-1)*@page_size ROWS FETCH NEXT @page_size ROWS ONLY,但深度分页(如 OFFSET > 数万)性能陡降,建议改用键集分页。

OFFSET FETCH 是 SQL Server 2012+ 唯一原生支持的“跳过-取回”分页语法,比 ROW_NUMBER() + 子查询更简洁、可读性更好,但必须配合 ORDER BY 使用,否则会报错。
OFFSET FETCH 必须带 ORDER BY,否则直接报错
SQL Server 强制要求 OFFSET 子句只能出现在含 ORDER BY 的查询末尾。不写或写错顺序都会触发错误:
Msg 102, Level 15, State 1, Line X Incorrect syntax near 'OFFSET'.
常见误写:
- 把
ORDER BY放在OFFSET后面(语法不允许) - 用
SELECT *但ORDER BY字段不在结果集中(比如按计算列排序却没选出来) - 在视图或内联表值函数里用了
OFFSET却没在调用处补ORDER BY
分页参数怎么算:page 和 page_size 要转成 offset 和 fetch
前端传的是第几页(page)和每页几条(page_size),SQL 层需转换为 OFFSET 和 FETCH NEXT 的数值:
- 第 1 页 →
OFFSET 0 ROWS - 第 2 页 →
OFFSET 10 ROWS(若page_size = 10) - 通用公式:
OFFSET (@page - 1) * @page_size ROWS -
FETCH NEXT @page_size ROWS ONLY(注意不能省略ONLY)
示例(查第 3 页,每页 20 条):
SELECT id, name, created_at FROM users ORDER BY id OFFSET 40 ROWS FETCH NEXT 20 ROWS ONLY;
性能隐患:OFFSET 越大,扫描行数越多
OFFSET 100000 ROWS 不代表跳过索引里的 10 万条,而是让 SQL Server 先定位并扫描前 10 万 + N 行,再丢弃——这会导致延迟陡增。
- 当
OFFSET超过几万,响应时间可能从毫秒级升到秒级 - 即使
ORDER BY字段有索引,也无法避免逻辑读放大 - 替代方案不是不用 OFFSET,而是改用「键集分页」(Keyset Pagination):用上一页最后一条的
id做条件,例如WHERE id > 12345 ORDER BY id OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY
真正麻烦的不是写法,是 OFFSET 在大数据偏移时的不可预测性——它看起来简单,但执行计划里扫过的行数会悄悄拖垮整个查询。用之前先看下执行计划里的「实际行数」。

















