Oracle中計算頁數的有效方法是什麼?
我們通過建構動態 SQL 查詢然後僅選擇部分結果在我們的 PL/SQL 過程中實現了分頁。
我們通過將原始查詢放入 SELECT 中來實現分頁,該 SELECT 僅從給定查詢中獲取某些 rownums,如下所示:
SELECT * FROM ( SELECT ROWNUM rnum, d.* FROM ( ' || pSql || ' [[filter]] [[sort]] ) d WHERE rownum < [[end]]) WHERE rnum> [[start]]
我能想到的實現頁面計數的唯一方法是對 pSql 中的所有記錄進行計數。然而,事實證明這非常耗費資源並且需要經常進行,因為我們提供了數據過濾,這反過來在 pSql 中創建了一個全新的查詢。
有沒有更有效的方法來進行記錄計數?
如果典型的使用模式是對所有數據進行分頁,那麼最終需要將所有記錄發送給客戶端。在這種情況下,為每個頁面重新查詢數據庫是低效的。您應該考慮執行一次查詢並通過客戶端的記憶體進行分頁。
另一方面,如果典型的使用模式是對非常少量的數據進行分頁,那麼這種方法可能是合適的。Nick Chammas 關於使用 ROW_NUMBER() 的評論由Tom Kyte 在 Oracle 雜誌的一篇文章中進行了充實。
SELECT * FROM ( SELECT /*+ first_rows(25) */ your_columns, Row_Number() Over (Order By something unique) rn FROM your_tables ) WHERE rn BETWEEN :n AND :m ORDER BY rn;
我建議你閱讀整篇文章。請特別注意按唯一內容排序的警告,以便頁面之間的結果保持一致(給定靜態數據):
對於這些分頁查詢,您需要按唯一的順序進行排序,以便每次都將 ROW_NUMBER 確定性地分配給行。
就像 Leigh 在另一個答案中提到的那樣。在使用者行為和負載方面考慮您的情況至關重要。話雖如此,有兩種選擇可以做到這一點。一個是 rownum,最近的是 row_number 分析函式。row_number 可以做更多的事情,但在這種特殊情況下,程式碼的外觀幾乎沒有差異。
select * from ( select rownum rn, last_name, first_name from clients where rownum<=100100 Order By upper(last_name),upper(first_name)) where rn>=100000 order by rn
對比
select * from ( select /*+ first_rows(25) */ last_name, first_name, row_number() over (order by upper(last_name),upper(first_name)) rn from clients_and_facilitators ) where rn between 100000 and 100100 order by rn
第一個耗時 269 毫秒,第二個耗時 4000 毫秒。注意我是如何在行數中使用大數字的。如果我把它降低到接近 1000-1100 ,那麼第一個需要 40 毫秒,第二個仍然需要 4000 毫秒。
這些結果似乎有些道理。第一個查詢僅對記錄進行排序,直到達到最大行。然後數據庫然後它只是過濾掉開始的行。第二個查詢是在過濾掉每條記錄之前計算它們的 row_number。這也是有道理的,因為 row_number 可以做更多的事情,並且可能更難優化。當更簡單的 rownum 方法更可優化時,更是如此。
分析表給出了兩種不同的評價方法。對於第一個查詢計數,使用 stopkey ,對於第二個視窗排序,使用 push rank。