1. 程式人生 > 其它 >分頁條件查詢_挖出一些分頁查詢的祕密

分頁條件查詢_挖出一些分頁查詢的祕密

技術標籤:分頁條件查詢

今天看下分頁查詢這個知識點,能挖出什麼樣的知識。

測試表中符合條件的記錄共32條,如果需要得到第10到第20條的記錄,我們能怎麼做?

SQL> select rownum, employee_id  2  from hr.employees a  3  where hire_date between to_date('20050101','yyyymmdd')   4                      and to_date('20060201','yyyymmdd');    ROWNUM EMPLOYEE_ID---------- -----------         1         202         2         101         3         103         4         105         5         110         6         111         7         116         8         117         9         121        10         123        11         125        12         129        13         130        14         131        15         138        16         142        17         146        18         147        19         150        20         151        21         152        22         159        23         160        24         162        25         168        26         170        27         175        28         180        29         185        30         188        31         189        32         19332 rows selected.

這個需求用到的,其實就是分頁,一般有兩種基本格式。

格式1

SQL> select *   2  from (select rownum as rowno, a.employee_id as id  3        from (select employee_id from hr.employees   4              where hire_date between to_date('20050101','yyyymmdd')   5                                  and to_date('20060201','yyyymmdd')) a  6        where rownum <= 20)  7  where rowno >= 10;     ROWNO         ID---------- ----------        10        123        11        125        12        129        13        130        14        131        15        138        16        142        17        146        18        147        19        150        20        15111 rows selected.

格式2

SQL> select *   2  from (select rownum as rowno, a.employee_id as id  3        from (select employee_id from hr.employees   4              where hire_date between to_date('20050101','yyyymmdd')   5                                  and to_date('20060201','yyyymmdd')) a)  6  where rowno between 10 and 20;     ROWNO         ID---------- ----------        10        123        11        125        12        129        13        130        14        131        15        138        16        142        17        146        18        147        19        150        20        15111 rows selected.

這兩種格式,既有相同,又有不同,我們看下。

1. 相同點

(1) 這兩種格式中內層的子查詢,從語義上理解,應該讀取所有符合條件的記錄,即32條,

select employee_id from hr.employees wherehire_datebetweento_date('20050101','yyyymmdd')   andto_date('20060201','yyyymmdd')

(2) 這兩種格式返回的結果集是相同的,都是正確的。

2. 不同點

我們用執行計劃,來看一下,

SQL>altersessionsetstatistics_level=all;Session altered.SQL> select * from table(dbms_xplan.display_cursor(null,null,'advanced -PROJECTION -bytes iostats,last'));

格式1實際只讀取了20條記錄,並不是32條,

f36722433cb662336247ce016cf1429d.png

格式2讀取了32條記錄,

55e4a1cadabdaaed080d5df66b9aebbe.png

這是為什麼?

在CBO模式下,Oracle可以將外層的查詢條件推到內層查詢中,以提高內層查詢的執行效率。對於格式1,第二層的查詢條件where rowno >= 10就可以被推入到內層查詢中,這樣Oracle查詢的結果一旦超過了rownum限制條件,就終止查詢將結果返回了。從執行計劃中,我們看到COUNT STOPKEY,點到為止,就是這個意思。

格式2,由於查詢條件between 10 and 20,是存在於查詢的第三層,而Oracle無法將第三層的查詢條件推到最內層,(即使推到最內層也沒有意義,因為最內層查詢不知道rowno代表什麼)。因此,對格式2,Oracle最內層返回給中間層的是所有滿足條件的資料,而中間層返回給最外層的也是所有資料。資料的過濾在最外層完成,從執行計劃中,我們看到COUNT,沒帶STOPKEY,說明需要統計所有的資料。

如果資料量有限,這兩種格式,相差無幾,如同上面的測試,COST相同,但是當資料量很龐大的時候,因為格式1不需要讀取所有資料,而格式2需要讀取所有資料,然後再根據rownum篩選,顯然格式1的效率要比格式2高。

我們再進一步,上面的測試,不知道大家看沒看出一些問題?

兩種格式中,子查詢都是如下,沒帶任何排序,因此如果這張表的資料是實時更新的,很可能每次執行返回的結果集是不同的,如果這個分頁的需求,對結果集的順序是有要求的,這條SQL就是錯的,而且可能很隱蔽,至於原因,《Oracle資料順序問題》中說明了,Oracle中沒有預設的資料讀取順序,唯一能讓結果集有序的操作就是增加order by子句,

select employee_id from hr.employees wherehire_datebetweento_date('20050101','yyyymmdd')   andto_date('20060201','yyyymmdd')

除此之外,可能還得注意,如果order by的欄位,存在相同記錄,查詢結果集可能還是不確定的,需要order by有可以唯一確定記錄的欄位,例如可以用唯一索引欄位、唯一約束欄位或rowid,具體案例可參考《一個分頁排序SQL查詢結果集不確定的案例》。

一個分頁操作,牽扯到的知識其實是很多的,如果不常用,確實容易忽視,就像我現在看之前經歷過的案例,可能也會忘,還是得重新瞭解,一方面可能是知識點沒吃透,另一方面還是需要注意日常的總結,形成適合自己的知識庫和檢索體系,在實踐中學,從學回到實踐,都是一種過程,只能慢慢體會了。

近期的熱文:

《2020資料技術嘉年華》

《MySQL異常訪問的熔斷機制》

《Oracle時間戳型別內部表示的轉換方式》

《Oracle的批量插入操作》

《資料庫結構文件的生成利器》

《主鍵約束索引的奇葩現象》

《如何判斷應用系統性能好不好?》

《Oracle Cloud建立19c資料庫》

《SQL工具集-格式化結果的SQL》

《如何捕獲問題SQL解決過度CPU消耗的問題》

《如何檢視JVM執行的堆記憶體情況》

《Oracle刪除欄位的方式和風險,你都瞭解麼?》

《登入緩慢的詭異問題》

《公眾號600篇文章分類和索引》