oracle高效分頁查詢總結


本文參考鏈接:http://blog.sina.com.cn/s/blog_8604ca230100vro9.html

探索查詢語句:

--分頁參數:size = 20 page = 2
--沒有order by的查詢
-- 嵌套子查詢,兩次篩選(推薦使用)
--SELECT *
-- FROM (SELECT ROWNUM AS rowno, t.*
-- FROM DONORINFO t
-- WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
-- AND TO_DATE ('20060731', 'yyyymmdd')
-- AND ROWNUM <= 20*2) table_alias
-- WHERE table_alias.rowno > 20*(2-1);        --耗時0.05s

-- 一次篩選(數據量大的時候,第一次查詢的數據量過大,明顯比上面慢,不推薦)
--select * from(
--SELECT ROWNUM AS rowno, t.*
--FROM DONORINFO t
--WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd') AND TO_DATE ('20060731', 'yyyymmdd')
--) r
--where r.rowno BETWEEN 20*(2-1)+1 and 20*2;      --耗時0.46s


--有order by的查詢
--嵌套子查詢,兩次篩選(推薦使用)
--SELECT *
--FROM (SELECT ROWNUM AS rowno,r.*
-- FROM(
-- SELECT * FROM DONORINFO t
-- WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
-- AND TO_DATE ('20060731', 'yyyymmdd')
-- ORDER BY t.BIRTHDAY desc
-- ) r
-- where ROWNUM <= 20*2 
-- ) table_alias
-- WHERE table_alias.rowno > 20*(2-1);                --耗時0.744s

-- 一次篩選(數據量大的時候,第一次查詢的數據量過大,明顯比上面慢,不推薦)
--select * from (
--SELECT ROWNUM AS rowno,r.*
--FROM(
--SELECT * FROM DONORINFO t
--WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
--AND TO_DATE ('20060731', 'yyyymmdd')
--ORDER BY t.BIRTHDAY desc
--) r
----where ROWNUM <= 20; --這里用>查不到數據 =也查不到數據 <= 或者 < 可以查到數據 
----where ROWNUM BETWEEN 20*(2-1)+1 AND 20*2; --查不到數據
----where ROWNUM <=20*2 and ROWNUM > 20*(2-1); --查不到數據
----這是因為查詢時,第一條生成的rownum為1,1>20不成立,1=20也不成立,所以這條數據就作廢了,依次類推,這樣就查不到任何一條數據
--) t 
--where t.rowno <=20*2 and t.rowno > 20*(2-1); --可以查到數據耗時:3.924s
---- where t.rowno BETWEEN 20*(2-1)+1 AND 20*2; --可以查到數據耗時:3.919s

--采用row_number() over 分頁函數
--select * 
--from(select d.*,row_number() over(order by d.BIRTHDAY) as rownumber 
--     from DONORINFO d
--     WHERE d.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
--                             AND TO_DATE ('20060731', 'yyyymmdd')
-- ) p 
--where p.rownumber BETWEEN 20*(2-1)+1 AND 20*2;  --耗時0.812s

select * from (
select * 
from(select d.*,row_number() over(order by d.BIRTHDAY) as rownumber 
     from DONORINFO d
     WHERE d.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
                             AND TO_DATE ('20060731', 'yyyymmdd')
 ) p 
where p.rownumber <20*2
) where rownumber > 20*(2-1);    -- 耗時0.813s

 

從以上探索比較,我們得知:

1、ROWNUM

  rownum總是從1開始的,第一條不滿足去掉的話,第二條的rownum 又成了1。依此類推,所以永遠沒有不滿足條件的記錄。

    可以這樣理解:rownum是一個序列,是Oracle數據庫從數據文件或緩沖區中讀取數據的順序。

    它取得第一條記錄則rownum值為1,第二條為2。依次類推。

    當使用“>、>=、=、between...and”這些條件時,從緩沖區或數據文件中得到的第一條記錄的rownum為1,不符合sql語句的條件,會被刪除,接着取下條。

    下條的rownum還會是1,又被刪除,依次類推,便沒有了數據。

  所以上限條件必須放在子查詢,而下限條件必須放在外層查詢。

2、between  and 和 >= and <=

這兩者查詢效率上來說沒有區別,between and 最終也是轉為>= and <=

所以select * from (select * from a where a.time >= to_date('19920324','yyyymmdd')) b where b.time <= to_date('20170324','yyyymmdd')

這樣的嵌套是沒有必要的,可以直接用between and。

3、Oracle通用分頁格式

對於沒有order by語句的分頁:

SELECT *
FROM (SELECT ROWNUM AS rowno, t.*
          FROM DONORINFO t
          WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd') AND TO_DATE ('20060731', 'yyyymmdd') AND ROWNUM <= page*size) table_alias WHERE table_alias.rowno > (page-1)*size; 

有order by語句的分頁

SELECT *
FROM (SELECT ROWNUM AS rowno,r.*
           FROM(SELECT * FROM DONORINFO t
                    WHERE t.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd') AND TO_DATE ('20060731', 'yyyymmdd') ORDER BY t.BIRTHDAY desc ) r where ROWNUM <= page*size ) table_alias WHERE table_alias.rowno > (page-1)*size;

另外我們也可以使用row_number() over函數:

select * 
from(select d.*,row_number() over(order by d.BIRTHDAY) as rownumber 
       from DONORINFO d
       WHERE d.BIRTHDAY BETWEEN TO_DATE ('19800101', 'yyyymmdd')
        AND TO_DATE ('20060731', 'yyyymmdd')
 ) p 
where p.rownumber BETWEEN size*(page-1)+1 AND page*size;

但是相比前面的並沒有什么優勢。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM