80-分页查询,不止写法

    据孔老先生说,茴香豆的茴字有四种写法,那oracle的分页查询又有多少种写法呢?
sql


分页查询,其实本质上就是topN查询的变种, 若是把topN的一部分结果集去掉,就变成了分页.性能优化


topN的基本写法,两层select,第一层先order by,第二层再用rownum:微信

select owner,object_name,object_id,rownum as rn from(select * from t1 where owner='SYS' order by object_id desc) where rownum<=20;oracle


有些初级开发人员有时会写成:函数

select owner,object_name,object_id,rownum as rn from t1 where owner='SYS'  and rownum<=20 order by object_id desc;性能


这种写法的逻辑可能存在问题,由于sql解析时会先执行rownum,随机先选出20条记录,再执行排序. 而不是常见业务须要的先排序,再取前20. 若是知足条件的所有结果集<=20, 那么逻辑也是没问题的.fetch




在上面topn的基础上, 再套一层select, 就变成了最多见的标准的三层select的分页查询写法(第一层排序,第二层给rownum取别名,获得topn,第三层去掉topn的前面部分):
优化

select owner,object_name,object_id,rn fromspa

  (select a.*,rownum as rn from.net

   (select * from t1 where owner='SYS' order by object_id desc) a where rownum<=20

  ) where rn>10;

执行计划中看到COUNT STOPKEY 为最佳(没有sort字样).



除了上面比较常见的写法, 还有其余几个不常见的写法:

1层select(12c+才支持的offset 写法,有时可能须要使用hint来纠正优化器执行计划):

select  owner,object_name,object_id,rownum as rn

from t1

where owner='SYS'

order by object_id desc

offset 10 rows fetch next 10 rows only;


执行计划中看到WINDOW NOSORT STOPKEY为最佳




2层select,用到了row_number分析函数(可能须要使用hint来纠正优化器执行计划):

SELECT * FROM

  (SELECT   owner,object_name,object_id,

            row_number() over (order by object_id desc) as rn

          FROM t1

        where owner='SYS'

)  WHERE RN<= 20 and RN > 10;


执行计划中看到WINDOW NOSORT STOPKEY为最佳



4层select,对于页数比较大的分页查询,某些状况下可使用:

with tmp as

(SELECT * FROM

    ( SELECT rid, ROWNUM as RN

       FROM

           (SELECT rowid as rid

             FROM t1

             where owner='SYS'

             order by object_id desc

            ) WHERE ROWNUM <= 500

    ) WHERE RN > 490

) select  /*+ use_nl(a) leading(b) */ owner,object_name,object_id,rn

from t1 a,tmp b

where a.rowid=b.rid;



下面的3层写法,是比较常见的低效分页写法,在分页前结果集大的状况,性能会比较差, 须要避免使用:

select * from

(

select a.*,rownum as rn  

from

(select owner,object_name,object_id

  from t1

  where owner= 'SYS'

   order by object_id desc

)a

) where rn>10 and rn<=20;

执行计划通常包含  SORT ORDER BY 的步骤.



掌握了分页写法,只是优化的第一步,下面咱们看一个生产案例,SQL代码以下:

这是一个取topn的SQL,先取topn(分页前结果集20万左右),再left join,写法彻底没问题,可是执行时间仍是比较长,须要24秒:


用hint调下执行计划,执行时间变成1秒:

hint:  /*+ monitor leading(p o) push_pred(co@sel$2) */


若是再建立一个core_userprofile表上orgid+UpdateDate+id 3字段联合索引, 那么这个SQL的执行时间估计也就是10毫秒如下了. (从24秒到10毫秒,这种性能的提升,靠硬件是没法实现的,现实中确实有不少相似的SQL,惋惜的是,咱们不少的决策人员, 只相信高级硬件才能解决性能问题,不知道有这些高级优化技巧)


总结:

    分页查询,写法只是第一步,写法正确的基础上,若是执行计划不佳,咱们能够经过oracle优化器提供的hint来调整执行计划(不须要改sql代码); 可是若是sql写法不佳,也是没有办法经过调整索引和执行计划进行优化. 


    写法和索引,是SQL优化的核心,在此基础上经过hint调整执行计划, 是更高级的技术, 须要更进一步的了解优化器特性,以人脑优化器代替电脑优化器.


    想提升SQL优化技能,看完个人线上培训课程(索引专题,SQL写法与改写专题)会大有帮助.

本文分享自微信公众号 - 老虎刘谈oracle性能优化(sql_tigerliu)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索