【Oracle】两种Oracle传统分页语句之效率比较
结论:方案二以不大的优势胜出,推荐使用如下SQL进行传统分页:
select * from (select tta.*,rownum as rn from ( your biz sql ) tta where rownum<=【end】 ) ttb where ttb.rn>【start】
至此,伸手党可以退散,较真党请继续往下看。
现有两种传统分页方案:
Oracle传统分页方案一:
select * from ( select ta.*,rownum as rn from ( your biz sql )ta )tb where 【start】<tb.rn and tb.rn<=【end】
介绍页面:https://www.cnblogs.com/heyang78/p/15750685.html
Oracle传统分页方案二:
select * from (select tta.*,rownum as rn from ( your biz sql ) tta where rownum<=【end】 ) ttb where ttb.rn>【start】
介绍页面:https://www.cnblogs.com/heyang78/p/15751235.html
为了验证哪种效率更高些,我们可以建个稍大的表:
create table emp8( id number(12), name nvarchar2(30), primary key(id) ) insert into emp8 select rownum,dbms_random.String('*',dbms_random.value(1,30)) from dual connect by level<10001
然后,设定我们的业务代码是:
biz sql: select * from emp8 order by name
查找范围限定在大于5500和小于等于6500的一千条记录上,两种方案的SQL就变成:
找5500~6500之间的数据 方案一: select * from ( select ta.*,rownum as rn from ( select * from emp8 order by name )ta )tb where 5500<tb.rn and tb.rn<=6500 方案二: select * from (select tta.*,rownum as rn from ( select * from emp8 order by name ) tta where rownum<=6500 ) ttb where ttb.rn>5500
对方案一执行解释计划是:
-------------------------------------------------------------------------------- Plan hash value: 1362420864 ------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 10000 | 566K| 19 (11)| 00:00:01 | |* 1 | VIEW | | 10000 | 566K| 19 (11)| 00:00:01 | | 2 | COUNT | | | | | | | 3 | VIEW | | 10000 | 439K| 19 (11)| 00:00:01 | | 4 | SORT ORDER BY | | 10000 | 439K| 19 (11)| 00:00:01 | | 5 | TABLE ACCESS FULL| EMP8 | 10000 | 439K| 17 (0)| 00:00:01 | PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- ------------------------------------------------------------------------------ Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("TB"."RN"<=6500 AND "TB"."RN">5500) Note ----- - dynamic statistics used: dynamic sampling (level=2) 已选择 21 行。
方案二的解释计划是:
Plan hash value: 4133749571 -------------------------------------------------------------------------------- - | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------- - PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 6500 | 368K| 19 (11)| 00:00:01 | |* 1 | VIEW | | 6500 | 368K| 19 (11)| 00:00:01 | |* 2 | COUNT STOPKEY | | | | | | | 3 | VIEW | | 10000 | 439K| 19 (11)| 00:00:01 | PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- |* 4 | SORT ORDER BY STOPKEY| | 10000 | 439K| 19 (11)| 00:00:01 | | 5 | TABLE ACCESS FULL | EMP8 | 10000 | 439K| 17 (0)| 00:00:01 | -------------------------------------------------------------------------------- - PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("TTB"."RN">5500) 2 - filter(ROWNUM<=6500) 4 - filter(ROWNUM<=6500) Note ----- - dynamic statistics used: dynamic sampling (level=2) 已选择 23 行。
好了,现在可以出比较表格了:
方案一 | 方案二 | |
select * from ( select ta.*,rownum as rn from ( select * from emp8 order by name )ta )tb where 5500<tb.rn and tb.rn<=6500 |
select * from (select tta.*,rownum as rn from ( |
|
cost | 19 | 19 |
rows | 在最后的筛选前,一直是一万行 | 到ttb时,便成了六千五百行 |
结论 | 效率稍低 | 效率稍高 |
解释 | 运行sql期间形成的两个view:ta和tb都是全结果集带着跑,最后才砍掉所有冗余数据。 | 运行sql期间形成的两个view:tta是全结果集,ttb是6500,砍了接近四成冗余数据后,最后再砍掉前面的5500行。 |
但是 | 劣势不明显 | 优势也不突出 |
到此,结论清晰了,一般可以选择方案二,但选方案一也不是不行,在中小应用中用户不细品未必能觉察出来。
当然,Oracle分页不止两种方案,有空我们继续探讨。
END
分类:
Oracle.分页
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2019-12-31 【Oracle】Count(*) 与 count(field) 结果会一样吗?
2019-12-31 Explain Plan试分析
2019-12-31 Oracle SQL Developer中查看解释计划Explain Plan的两种方法
2019-12-31 借助rownum中求Oracle表中前三名(三甲:状元榜眼探花)的方法(总计三种方法,以讲述rownum的使用为主)
2019-12-31 莫名其妙的Explain Plan
2019-12-31 我的T440p出现怪事情了
2017-12-31 x为正变数,求y=x^3/(x^4+4)的最大值