Oracle 数据库实现分页,分两个主流版本写法,Oracle 11g 及更早版本没有 LIMIT,核心依靠 ROWNUM 伪列嵌套子查询实现分页,Oracle 12c 之后新增原生 OFFSET FETCH NEXT 语法,可以直接写分页,不需要多层嵌套,面试和老项目高频考点是 ROWNUM 三层嵌套写法,很多初学者直接在外层写 where rownum between 11 and 20,查询结果是空,底层原因是 ROWNUM 是在数据行返回的时候才赋值,是动态生成伪列,不是提前排序好的编号,必须先排序,再生成行号,所以要嵌套子查询,同时分页一定要搭配 ORDER BY 稳定排序,如果没有排序,每次分页数据会乱序重复,这是分页最常见 bug,另外大表深分页也就是页码很大的时候,ROWNUM 方式性能会下降,因为前面大量数据依然要扫描。
分页写法出错底层原因,第一是不理解 ROWNUM 伪列生成时机,rownum 是边查询边编号,不能直接大于某个数字,rownum>10 永远查不出数据。第二是忘记排序,分页数据不稳定,翻页出现重复或者丢失记录。第三是混淆 12c 新语法,老版本 Oracle 不支持 OFFSET FETCH,直接写会报语法错误。第四是深分页性能问题,大表千万级数据,页码很大,扫描开销很高,可以优化成基于主键的 seek 分页。
方案一 Oracle11g ROWNUM 三层嵌套分页(经典面试写法)
需求:每页 10 条,查询第 2 页,也就是第 11~20 条数据
SELECT
FROM (
SELECT t., ROWNUM AS rn
FROM (
SELECT FROM emp ORDER BY emp_id
) t
WHERE ROWNUM <= 20
) temp
WHERE temp.rn >= 11;
拆解说明
1 最内层:原始查询 + ORDER BY,保证数据有序
2 中间层:对排序后的结果生成 ROWNUM 伪列,并且截取到上限 20
3 最外层:筛选 rn 大于等于 11,得到第二页数据
公式:
每页 size,当前 page
起始 = (page-1)size + 1
结束 = page size
方案二 Oracle12c+ 原生 OFFSET FETCH NEXT 分页
SELECT
FROM emp
ORDER BY emp_id
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
含义:跳过前面 10 行,取出接下来 10 行,也就是第二页
语法要点
1 必须搭配 ORDER BY,否则排序不稳定
2 OFFSET 跳过行数,FETCH NEXT 每页条数
3 写法简洁,是新版 Oracle 推荐分页语法
深分页优化思路
1 主键 seek 分页,避免扫描前面大量行,适合千万级大表
示例:上一页最后主键 id,下一页直接 where id > 上一页 id order by id fetch next 10 rows only
2 建立排序字段对应的索引,避免排序产生全表扫描,提升分页速度
高频易错点
1 错误写法:SELECT FROM emp WHERE ROWNUM BETWEEN 11 AND 20 结果为空
原因:ROWNUM 从 1 开始递增,第一条数据 rownum=1,永远不会先出现 rownum=11
2 没有 ORDER BY,翻页数据错乱重复
3 11g 不能使用 OFFSET FETCH,执行直接报语法错误
4 排序字段存在重复值,依然可能翻页重复,最好使用唯一主键作为排序字段
Oracle 分页核心就是老版本 ROWNUM 嵌套,新版本 OFFSET FETCH,重点掌握 ROWNUM 伪列原理,排序是分页必不可少的条件,大表深分页需要额外优化索引和主键 seek。
【常见问题】
问题 1 Oracle 数据库实现分页功能 为什么 rownum between 11 and 20 查不到数据
回答 1 Oracle 数据库实现分页功能,ROWNUM 是查询过程动态赋值,从 1 开始,不存在一开始就 rownum=11,所以直接 between 11 and 20 没有结果,必须嵌套子查询先生成 rn 编号。
问题 2 Oracle 数据库实现分页功能 12c 是不是可以不用 rownum
回答 2 Oracle 数据库实现分页功能,Oracle12c 新增 OFFSET FETCH NEXT 原生分页语法,可以不用 ROWNUM 嵌套,写法更加简洁,但是老版本 11g 不支持该语法。
问题 3 Oracle 数据库实现分页功能 深分页很慢怎么优化
回答 3 Oracle 数据库实现分页功能,深分页慢是因为需要扫描前面大量记录,可以给排序主键建立索引,改用主键 seek 方式,根据上一页最后主键值过滤,减少扫描行数。
【免责申明】
本内容仅为 Oracle 分页 SQL 学习参考,不同 Oracle 版本语法支持存在差异,正式业务请结合表结构索引优化 SQL,因 SQL 写法错误造成数据错乱性能问题,由使用者自行承担。


