Oracle 12c+应优先用OFFSET/FETCH FIRST实现分页,因其严格按ORDER BY→OFFSET→FETCH顺序执行,语义清晰、结果可控;而ROWNUM需两层子查询且在排序前赋值,WHERE ROWNUM BETWEEN直接无效。
fetch first 能直接表达分页意图,而 rownum 必须靠嵌套“绕弯子”才能拿到正确结果。
FETCH FIRST 必须和 ORDER BY 在同一层 SELECT 中写
它不是装饰性语法,而是执行顺序的硬约束:Oracle 会严格按 ORDER BY → OFFSET → FETCH FIRST 执行。漏掉 ORDER BY,语句能跑通,但返回哪几行完全不可控——因为没排序时,“前 N 行”没有定义。
-
FETCH FIRST 10 ROWS ONLY合法,OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY也合法;但FETCH FIRST -1 ROWS ONLY直接报ORA-00933 - 不能把带
FETCH FIRST的查询塞进子查询里再 SELECT —— 那会触发 ORA-00907 “missing right parenthesis” - 如果只是取 Top-N(比如查工资最高的 5 人),用
FETCH FIRST比写两层子查询少 8~12 个字符,且意图一目了然
ROWNUM 分页为什么总要两层子查询
ROWNUM 是在结果集生成“过程中”就编号的,从 1 开始、只增不跳,且分配发生在 ORDER BY 之前。所以 WHERE ROWNUM > 10 永远为空,WHERE ROWNUM BETWEEN 11 AND 20 也永远为空。
- 必须先在内层子查询中
ORDER BY+WHERE ROWNUM <= 20,把前 20 行稳住;再在外层用别名列(如rnum)筛> 10 - 内层没
ORDER BY?那ROWNUM <= 20取的是随机 20 行,外层再怎么筛都错 - 外层再加
ORDER BY可能破坏逻辑顺序,尤其在并行执行或复杂视图里
性能差异实际体现在哪儿
两者都要全量排序(除非排序字段有索引),但优化器对 FETCH FIRST 更友好:执行计划里常能看到 WINDOW SORT PUSHED RANK 或直接剪枝,而 ROWNUM 嵌套容易让优化器误判中间结果集大小。
- 大表分页到第 10000 页时,
OFFSET 99990 ROWS FETCH NEXT 10 ROWS ONLY虽然也要跳过 99990 行,但 Oracle 知道“只需取 10 行”,临时空间压力比 ROWNUM 套两层子查询略低 - 如果排序字段无索引,
ROW_NUMBER() OVER (ORDER BY ...)和ROWNUM方案都会慢,且多一次窗口函数开销;FETCH FIRST至少少一层函数调用 -
OFFSET超出总行数(比如总共 100 行却OFFSET 200),FETCH FIRST安静返回空集;ROWNUM方案若内层上限设小了,可能直接漏数据
真正容易被忽略的是:FETCH FIRST 不是“更高级的语法糖”,它是语义层面的修正——把“先排序、再切片”这件事从开发者的脑内推理,变成了数据库执行引擎的强制契约。一旦跨版本混用(比如在 11g 里硬写 FETCH FIRST),或者在 12c+ 里漏掉 ORDER BY,问题不会立刻报错,而是以“数据偶尔错乱”的方式潜伏下来。


















