fetch first 在 oracle 19c 中完全可用,是限制行数的首选方式;必须与 order by 同级使用,否则报 ora-00933 或静默失效,因其为窗口级截断而非过滤操作。

FETCH FIRST 在 Oracle 19c 中完全可用,且是限制返回行数的首选方式——它语义清晰、写法扁平、不依赖嵌套,只要注意 ORDER BY 必须同级存在,就不会出错。
FETCH FIRST 必须和 ORDER BY 在同一层 SELECT 中
这是最常踩的坑:把 ORDER BY 放在子查询里,外层再加 FETCH FIRST,Oracle 会直接报 ORA-00933 或静默忽略 FETCH。因为 FETCH 是窗口级截断操作,不是过滤条件。
- ✅ 正确写法:
SELECT * FROM emp ORDER BY hire_date DESC FETCH FIRST 5 ROWS ONLY - ❌ 错误写法:
SELECT * FROM (SELECT * FROM emp ORDER BY hire_date DESC) FETCH FIRST 5 ROWS ONLY(缺少外层ORDER BY) - ❌ 更隐蔽的错误:
SELECT * FROM (SELECT * FROM emp ORDER BY hire_date DESC) t WHERE ROWNUM (混用两种机制,失去 <code>FETCH优势)
分页场景下用 OFFSET + FETCH NEXT 而非 FETCH FIRST
虽然 FETCH FIRST 10 ROWS ONLY 和 FETCH NEXT 10 ROWS ONLY 效果一致,但分页时推荐显式写 OFFSET M ROWS FETCH NEXT N ROWS ONLY,语义更贴近“跳过前 M 行,取接下来 N 行”。
-
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY等价于第 1 页 -
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY是第 3 页(每页 10 条) -
OFFSET值可以是 0 或正整数;负数或非数字会触发ORA-00933 - 如果
OFFSET超过总行数,结果为空集,不报错
ROWNUM 方式在 19c 仍能用,但没必要主动选它
老版本兼容写法如 SELECT * FROM (SELECT * FROM emp ORDER BY salary DESC) WHERE ROWNUM 在 19c 依然有效,但它有硬伤:
- 无法表达“跳过前 10 行再取 10 行”,必须两层嵌套才能模拟
OFFSET -
ROWNUM分配发生在排序之前,若漏掉内层ORDER BY,结果完全不可控 - 优化器对
FETCH的剪枝更积极,大表 + 无索引排序字段时,FETCH执行计划通常比ROWNUM嵌套更优 -
WHERE ROWNUM > 10永远返回空——这是伪列机制决定的,改不了
WITH TIES 和 PERCENT 的实用边界
WITH TIES 和百分比语法虽支持,但实际使用要谨慎:
-
FETCH FIRST 5 ROWS WITH TIES会多返回与第 5 行排序键相同的全部行,可能返回 7 行甚至更多——适合榜单类需求,不适合严格分页 -
FETCH FIRST 10 PERCENT ROWS ONLY计算基于最终排序结果集行数,不是原表;若结果集只有 3 行,10 PERCENT向下取整为 0,返回空 -
FIRST 0 ROWS ONLY合法,等效于WHERE 1=0;但FIRST -1 ROWS ONLY会立即报ORA-00933
真正容易被忽略的是:即使写了 FETCH FIRST,只要没建好排序字段的索引,Oracle 仍要完成全量排序再截断——性能瓶颈不在语法,而在执行路径。别只盯着写法,先看执行计划里的 SORT ORDER BY STOPKEY 是否出现。











