為什麼需要按鍵分頁的工具支援?

大家好! 我是一名後端開發人員,用 Java + Spring 編寫微服務。 我在 Tinkoff 的一個內部產品開發團隊工作。

為什麼需要按鍵分頁的工具支援?

在我們的團隊中,經常會出現優化 DBMS 中的查詢的問題。 您總是希望速度更快一點,但您並不總是能夠透過精心建立的索引來實現 — 您必須尋找一些解決方法。 在一次在網路上徘徊尋找使用資料庫時合理優化的過程中,我發現 馬庫斯溫納德 (Marcus Wynand) 的部落格為您帶來無盡的幫助,《SQL 效能解釋》一書的作者。 這是一種罕見的部落格類型,您可以在其中連續閱讀所有文章。

我想為您翻譯馬庫斯的一篇短文。 在某種程度上,它可以被稱為一份宣言,旨在引起人們對根據 SQL 標準的偏移操作性能的古老但仍然相關的問題的關注。

有些地方我會補充作者的解釋和評論。 我將把所有這些地方稱為“大約”。 為了更清楚

簡短介紹

我想很多人都知道透過偏移量進行頁面選擇是多麼有問題且緩慢。 您是否知道它可以輕鬆地被更有效率的設計所取代?

因此,offset 關鍵字告訴資料庫跳過請求中的前 n 筆記錄。 然而,資料庫仍然需要按照給定的順序從磁碟讀取前n筆記錄(注意:如果指定則應用排序),只有這樣才有可能傳回從n+1開始的記錄。 最有趣的是,問題不在於DBMS中的具體實現,而在於依照標準的原始定義:

…行首先根據然後透過刪除中指定的行數來限制從一開始就...
-SQL:2016, Part 2, 4.15.3 衍生表(註:目前使用最多的標準)

這裡的關鍵點是 offset 採用單一參數 - 要跳過的記錄數,僅此而已。 依照這個定義,DBMS 只能檢索所有記錄,然後丟棄不需要的記錄。 顯然,這種偏移量的定義迫使我們做額外的工作。 而且無論是 SQL 還是 NoSQL 都不重要。

只是再痛一點

偏移的問題不止於此,原因如下。 如果在從磁碟讀取兩頁資料之間,另一個操作插入了一條新記錄,這種情況會發生什麼?

為什麼需要按鍵分頁的工具支援?

當使用offset 跳過前一頁的記錄時,在不同頁的讀取之間添加新記錄的情況下,您很可能會得到重複項(注意:當我們使用order by 結構逐頁讀取時,這是可能的,然後在我們的輸出中間它可能會得到一個新條目)。

該圖清楚地描繪了這種情況。 基底讀取前10 筆記錄,然後插入一筆新記錄,這會將所有讀取的記錄偏移1。然後基底從接下來的10 筆記錄中取得一個新頁,並且不是從第11 筆記錄開始,而是從第10 筆記錄開始。XNUMX、複製此記錄。 還有與此表達式的使用相關的其他異常,但這是最常見的。

正如我們已經發現的,這些不是特定 DBMS 或其實現的問題。 問題在於根據 SQL 標準定義分頁。 我們告訴 DBMS 要取得哪個頁面或要跳過多少筆記錄。 資料庫根本無法優化這樣的請求,因為這方面的資訊太少。

另外值得澄清的是,這不是特定關鍵字的問題,而是查詢語意的問題。 還有其他幾種語法在其問題性質上是相同的:

  • offset 關鍵字如前所述。
  • 兩個關鍵字 limit [offset] 的構造(儘管 limit 本身並沒有那麼糟)。
  • 根據行編號(例如 row_number()、rownum 等)按下限進行過濾。

所有這些表達式只是告訴您要跳過多少行,沒有其他資訊或上下文。

在本文後面,將使用 offset 關鍵字作為所有這些選項的摘要。

沒有OFFSET的生活

現在讓我們想像一下,如果沒有這些問題,我們的世界會是什麼樣子。 事實證明,沒有偏移量的生活並不那麼困難:使用 select,您可以使用 where 中的條件僅選擇那些我們尚未看到的行(注意:即那些不在上一頁上的行)。

在這種情況下,我們從這樣一個事實開始:選擇是在有序集上執行的(好舊的 order by)。 由於我們有一個有序集,因此我們可以使用一個相當簡單的篩選器來只取得上一頁最後一筆記錄後面的資料:

    SELECT ...
    FROM ...
    WHERE ...
    AND id < ?last_seen_id
    ORDER BY id DESC
    FETCH FIRST 10 ROWS ONLY

這就是該方法的全部原理。 當然,按多列排序時事情會變得更有趣,但想法仍然是一樣的。 值得注意的是,這種設計適用於許多 NoSQL-決定。

這種方法稱為尋找方法或鍵集分頁。 它解決了浮動結果問題(注意:前面描述過的頁面讀取之間寫入的情況),當然,我們都喜歡它,它比經典偏移更快、更穩定。 穩定性在於請求處理時間不會與請求的表數量成正比增加(註:如果你想詳細了解不同分頁方法的工作原理,可以 看看作者的介紹。 您也可以在那裡找到不同方法的比較基準)。

其中一張投影片 談論那個當然,按鍵分頁並不是萬能的-它有其限制。 最重要的是她不具備閱讀隨機頁面的能力(注意:不一致)。 然而,在無限滾動的時代(註:在前端),這並不是這樣的問題。 無論如何,指定點擊頁碼在 UI 設計中都是一個糟糕的決定(附註:文章作者的觀點)。

工具呢?

由於缺乏對此方法的工具支持,按鍵分頁通常不合適。 大多數開發工具(包括各種框架)不允許您準確選擇分頁的執行方式。

由於所描述的方法需要所使用的技術的端到端支援——從 DBMS 到在瀏覽器中執行無休止滾動的 AJAX 請求,這一事實使情況更加惡化。 現在您必須同時為所有頁面指定一組鍵,而不是僅指定頁碼。

然而,支援按鍵分頁的框架數量正在逐漸增加。 這是我們目前所擁有的:

(附註:由於翻譯時某些庫自 2017-2018 年以來未更新,因此刪除了一些連結。如果您有興趣,可以查看原始來源。)

此刻就需要您的幫助。 如果您開發或支援使用分頁的框架,那麼我請求,我強烈建議,我懇求您為按鍵上的分頁提供本機支援。 如果您有疑問或需要協助,我將很樂意提供協助(論壇, Twitter, 聯絡表)(註:根據我與馬庫斯的經驗,我可以說他非常熱衷於傳播這個話題)。

如果您使用現成的解決方案,您認為值得支援按鍵分頁,請建立請求,甚至提供現成的解決方案(如果可能)。 您也可以連結到這篇文章。

結論

按鍵分頁這樣簡單又有用的方法之所以沒有普及,並不是因為它在技術上難以實現或需要付出很大的努力。 主要原因是許多人習慣於查看和使用偏移 - 這種方法是由標準本身決定的。

因此,很少有人考慮改變分頁方法,正因為如此,框架和函式庫的工具支援發展得很差。 因此,如果無偏移分頁的想法和目標離您很近,請幫助傳播它!

來源: https://use-the-index-luke.com/no-offset
作者:馬庫斯‧維南德

來源: www.habr.com

添加評論