Oracle

Oracle中計算頁數的有效方法是什麼?

  • February 12, 2017

我們通過建構動態 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。

引用自:https://dba.stackexchange.com/questions/6058