的寫法 80分頁查詢,不止寫法

2021-10-14 19:17:18 字數 3218 閱讀 6495

據孔老先生說,茴香豆的茴字有四種寫法,那oracle的分頁查詢又有多少種寫法呢?

分頁查詢,其實本質上就是topn查詢的變種, 如果把topn的一部分結果集去掉,就變成了分頁.

topn的基本寫法,兩層select,第一層先order by,第二層再用rownum:

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

有些初級開發人員有時會寫成:

select owner,object_name,object_id,rownum as rn fromt1 whereowner='sys'and rownum<=20order by object_id desc;

這種寫法的邏輯可能存在問題,因為sql解析時會先執行rownum,隨機先選出20條記錄,再執行排序. 而不是常見業務需要的先排序,再取前20. 如果滿足條件的全部結果集<=20, 那麼邏輯也是沒問題的.

在上面topn的基礎上, 再套一層select, 就變成了最常見的標準的三層select的分頁查詢寫法(第一層排序,第二層給rownum取別名,得到topn,第三層去掉topn的前面部分):

select owner,object_name,object_id,rn from

(select a.*,rownum as rn from

(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秒:

如果再建立乙個core_userprofile表上orgid+updatedate+id 3欄位聯合索引, 那麼這個sql的執行時間估計也就是10毫秒以下了. (從24秒到10毫秒,這種效能的提高,靠硬體是無法實現的,現實中確實有很多類似的sql,可惜的是,我們很多的決策人員, 只相信高階硬體才能解決效能問題,不知道有這些高階優化技巧)

總結:

分頁查詢,寫法只是第一步,寫法正確的基礎上,如果執行計畫不佳,我們可以通過oracle優化器提供的hint來調整執行計畫(不需要改sql**); 但是如果sql寫法不佳,也是沒有辦法通過調整索引和執行計畫進行優化. 

寫法和索引,是sql優化的核心,在此基礎上通過hint調整執行計畫, 是更高階的技術, 需要更進一步的了解優化器特性,以人腦優化器代替電腦優化器.

想提高sql優化技能,看完我的線上培訓課程(索引專題,sql寫法與改寫專題)會大有幫助.

Play 2 1 分頁寫法

不知道play實現分頁的方法有多少。play提供的一種是這樣的。首先實現乙個分頁類 public static class page public long gettotalrowcount public int getpageindex public listgetlist public bool...

Oracle SQL和DB2分頁查詢寫法介紹

db2分頁查詢和oracle sql中的分頁查詢語句寫法都不太一樣,下面就為您介紹db2分頁查詢和其他資料庫中分頁查詢的區別,希望對您有所幫助。oracle分頁查詢寫法 一 oracle select from select rownum,name from table where rownum e...

Oracle SQL和DB2分頁查詢寫法介紹

db2分頁查詢和oracle sql中的分頁查詢語句寫法都不太一樣,下面就為您介紹db2分頁查詢和其他資料庫中分頁查詢的區別,希望對您有所幫助。oracle分頁查詢寫法 一 oracle select from select rownum,name from table where rownum e...