不需要擔心數據庫性能優化問題的日子已經一去不復返了。
隨著時代的進步,隨著野心勃勃的企業想要變成下一個 Facebook,隨著為機器學習預測收集盡可能多數據的想法的出現,作為開發人員,我們要不斷地打磨我們的 API,讓它們提供可靠和有效的端點,從而毫不費力地瀏覽海量數據。
如果你做過后臺開發或數據庫架構,你可能是這么分頁的:
如果你真的是這么分頁,那么我不得不抱歉地說,你這樣做是錯的。
你不以為然?沒關系。Slack、Shopify 和 Mixmax 這些公司都在用我們今天將要討論的方式進行分頁。
我想你很難找出一個不使用 OFFSET 和 LIMIT 進行數據庫分頁的人。對于簡單的小型應用程序和數據量不是很大的場景,這種方式還是能夠“應付”的。
如果你想從頭開始構建一個可靠且高效的系統,在一開始就要把它做好。
今天我們將探討已經被廣泛使用的分頁方式存在的問題,以及如何實現高性能分頁。
1、OFFSET 和 LIMIT 有什么問題?
正如前面段落所說的那樣,OFFSET 和 LIMIT 對于數據量少的項目來說是沒有問題的。
但是,當數據庫里的數據量超過服務器內存能夠存儲的能力,并且需要對所有數據進行分頁,問題就會出現。
為了實現分頁,每次收到分頁請求時,數據庫都需要進行低效的全表掃描。
什么是全表掃描?全表掃描 (又稱順序掃描) 就是在數據庫中進行逐行掃描,順序讀取表中的每一行記錄,然后檢查各個列是否符合查詢條件。這種掃描是已知最慢的,因為需要進行大量的磁盤 I/O,而且從磁盤到內存的傳輸開銷也很大。
這意味著,如果你有 1 億個用戶,OFFSET 是 5 千萬,那么它需要獲取所有這些記錄 (包括那么多根本不需要的數據),將它們放入內存,然后獲取 LIMIT 指定的 20 條結果。
也就是說,為了獲取一頁的數據:
10萬行中的第5萬行到第5萬零20行
需要先獲取 5 萬行。這么做是多么低效?
左邊的 Schema SQL 將插入 10 萬行數據,右邊有一個性能很差的查詢和一個較好的解決方案。只需單擊頂部的 Run,就可以比較它們的執行時間。第一個查詢的運行時間至少是第二個查詢的 30 倍。
數據越多,情況就越糟。看看我對 10 萬行數據進行的 PoC。
現在你應該知道這背后都發生了什么:OFFSET 越高,查詢時間就越長。
2、替代方案
你應該這樣做:
這是一種基于指針的分頁。
你要在本地保存上一次接收到的主鍵 (通常是一個 ID) 和 LIMIT,而不是 OFFSET 和 LIMIT,那么每一次的查詢可能都與此類似。
為什么?因為通過顯式告知數據庫最新行,數據庫就確切地知道從哪里開始搜索(基于有效的索引),而不需要考慮目標范圍之外的記錄。
比較這個查詢:
和優化的版本:
返回同樣的結果,第一個查詢使用了 12.80 秒,而第二個僅用了 0.01 秒。
要使用這種基于游標的分頁,需要有一個惟一的序列字段 (或多個),比如惟一的整數 ID 或時間戳,但在某些特定情況下可能無法滿足這個條件。
我的建議是,不管怎樣都要考慮每種解決方案的優缺點,以及需要執行哪種查詢。
如果我們的表沒有主鍵,比如是具有多對多關系的表,那么就使用傳統的 OFFSET/LIMIT 方式,只是這樣做存在潛在的慢查詢問題。我建議在需要分頁的表中使用自動遞增的主鍵,即使只是為了分頁。
審核編輯:劉清
-
存儲器
+關注
關注
38文章
7528瀏覽量
164356 -
PoC
+關注
關注
1文章
71瀏覽量
20580 -
SQL
+關注
關注
1文章
775瀏覽量
44255 -
機器學習
+關注
關注
66文章
8441瀏覽量
133094
原文標題:別再用 offset 和 limit 分頁了,性能太差!
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
PGA308為什么加兩個offset,Coarse offset及Fine offset?用一個offset不能調零嗎?
關于選型時POWER MOSFET的Id的Silicon limit和package limit的看法
OFFSET約束問題
看看nginx的連接頻率limit_conn_module和請求頻率limit_req_module限制模塊
CDMA Access pn offset與距離的公式測定
Timing Groups and OFFSET Const
DC Offset Auto-Calibration of
Current-Limit Switch Is Digita
![Current-<b class='flag-5'>Limit</b> Switch Is Digita](https://file1.elecfans.com//web2/M00/A4/DD/wKgZomUMNgKADbIAAAAYXNF88Oc700.gif)
OFFSET約束的寫法(OFFSET IN和OFFSET OUT)
![<b class='flag-5'>OFFSET</b>約束的寫法(<b class='flag-5'>OFFSET</b> IN和<b class='flag-5'>OFFSET</b> OUT)](https://file1.elecfans.com//web2/M00/A6/A7/wKgZomUMP2qAQXNOAAAY4GwRQDU482.png)
ngx_dynamic_limit_req_module IP動態鎖定工具
![ngx_dynamic_<b class='flag-5'>limit</b>_req_module IP動態鎖定工具](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
MySQL用limit為什么會影響性能
offset新探索:雙管齊下,加速大數據量查詢
![<b class='flag-5'>offset</b>新探索:雙管齊下,加速大數據量查詢](https://file.elecfans.com/web2/M00/7D/F3/pYYBAGN_Ew2ARTElAACl7e-leQ4309.png)
VSync offset定義的方法
![VSync <b class='flag-5'>offset</b>定義的方法](https://file1.elecfans.com/web2/M00/AF/E3/wKgaomVcaweAVppaAABBsCFjiiE498.jpg)
評論