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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索