【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 (
     select * from emp8 order by name
) tta where rownum<=6500 ) ttb where ttb.rn>5500

cost 19 19
rows 在最后的筛选前,一直是一万行 到ttb时,便成了六千五百行
结论 效率稍低 效率稍高
解释 运行sql期间形成的两个view:ta和tb都是全结果集带着跑,最后才砍掉所有冗余数据。 运行sql期间形成的两个view:tta是全结果集,ttb是6500,砍了接近四成冗余数据后,最后再砍掉前面的5500行。
但是 劣势不明显 优势也不突出

到此,结论清晰了,一般可以选择方案二,但选方案一也不是不行,在中小应用中用户不细品未必能觉察出来。

当然,Oracle分页不止两种方案,有空我们继续探讨。

END

posted @   逆火狂飙  阅读(274)  评论(0编辑  收藏  举报
编辑推荐:
· 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)的最大值
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东
点击右上角即可分享
微信分享提示