<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          別再用 offset 和 limit 分頁了,性能太差!

          共 1862字,需瀏覽 4分鐘

           ·

          2022-08-03 13:30

          點(diǎn)擊關(guān)注公眾號,實(shí)用技術(shù)文章及時(shí)了解

          不需要擔(dān)心數(shù)據(jù)庫性能優(yōu)化問題的日子已經(jīng)一去不復(fù)返了。

          隨著時(shí)代的進(jìn)步,隨著野心勃勃的企業(yè)想要變成下一個(gè) Facebook,隨著為機(jī)器學(xué)習(xí)預(yù)測收集盡可能多數(shù)據(jù)的想法的出現(xiàn),作為開發(fā)人員,我們要不斷地打磨我們的 API,讓它們提供可靠和有效的端點(diǎn),從而毫不費(fèi)力地瀏覽海量數(shù)據(jù)。

          如果你做過后臺開發(fā)或數(shù)據(jù)庫架構(gòu),你可能是這么分頁的:

          如果你真的是這么分頁,那么我不得不抱歉地說,你這樣做是錯的。

          你不以為然?沒關(guān)系。SlackShopifyMixmax 這些公司都在用我們今天將要討論的方式進(jìn)行分頁。

          我想你很難找出一個(gè)不使用 OFFSETLIMIT 進(jìn)行數(shù)據(jù)庫分頁的人。對于簡單的小型應(yīng)用程序和數(shù)據(jù)量不是很大的場景,這種方式還是能夠“應(yīng)付”的。

          如果你想從頭開始構(gòu)建一個(gè)可靠且高效的系統(tǒng),在一開始就要把它做好。

          今天我們將探討已經(jīng)被廣泛使用的分頁方式存在的問題,以及如何實(shí)現(xiàn)高性能分頁。

          1.OFFSET 和 LIMIT 有什么問題?

          正如前面段落所說的那樣,OFFSETLIMIT 對于數(shù)據(jù)量少的項(xiàng)目來說是沒有問題的。

          但是,當(dāng)數(shù)據(jù)庫里的數(shù)據(jù)量超過服務(wù)器內(nèi)存能夠存儲的能力,并且需要對所有數(shù)據(jù)進(jìn)行分頁,問題就會出現(xiàn)。

          為了實(shí)現(xiàn)分頁,每次收到分頁請求時(shí),數(shù)據(jù)庫都需要進(jìn)行低效的全表掃描。

          什么是全表掃描?全表掃描 (又稱順序掃描) 就是在數(shù)據(jù)庫中進(jìn)行逐行掃描,順序讀取表中的每一行記錄,然后檢查各個(gè)列是否符合查詢條件。這種掃描是已知最慢的,因?yàn)樾枰M(jìn)行大量的磁盤 I/O,而且從磁盤到內(nèi)存的傳輸開銷也很大。

          這意味著,如果你有 1 億個(gè)用戶,OFFSET 是 5 千萬,那么它需要獲取所有這些記錄 (包括那么多根本不需要的數(shù)據(jù)),將它們放入內(nèi)存,然后獲取 LIMIT 指定的 20 條結(jié)果。

          也就是說,為了獲取一頁的數(shù)據(jù):

          10萬行中的第5萬行到第5萬零20行

          需要先獲取 5 萬行。這么做是多么低效?

          如果你不相信,可以看看這個(gè)例子:

          https://www.db-fiddle.com/f/3JSpBxVgcqL3W2AzfRNCyq/1

          左邊的 Schema SQL 將插入 10 萬行數(shù)據(jù),右邊有一個(gè)性能很差的查詢和一個(gè)較好的解決方案。只需單擊頂部的 Run,就可以比較它們的執(zhí)行時(shí)間。第一個(gè)查詢的運(yùn)行時(shí)間至少是第二個(gè)查詢的 30 倍。

          數(shù)據(jù)越多,情況就越糟。看看我對 10 萬行數(shù)據(jù)進(jìn)行的 PoC。

          https://github.com/IvoPereira/Efficient-Pagination-SQL-PoC

          現(xiàn)在你應(yīng)該知道這背后都發(fā)生了什么:OFFSET 越高,查詢時(shí)間就越長。

          2.替代方案

          你應(yīng)該這樣做:

          這是一種基于指針的分頁。

          你要在本地保存上一次接收到的主鍵 (通常是一個(gè) ID) 和 LIMIT,而不是 OFFSETLIMIT,那么每一次的查詢可能都與此類似。

          為什么?因?yàn)橥ㄟ^顯式告知數(shù)據(jù)庫最新行,數(shù)據(jù)庫就確切地知道從哪里開始搜索(基于有效的索引),而不需要考慮目標(biāo)范圍之外的記錄。

          比較這個(gè)查詢:

          和優(yōu)化的版本:

          返回同樣的結(jié)果,第一個(gè)查詢使用了 12.80 秒,而第二個(gè)僅用了 0.01 秒。

          要使用這種基于游標(biāo)的分頁,需要有一個(gè)惟一的序列字段 (或多個(gè)),比如惟一的整數(shù) ID 或時(shí)間戳,但在某些特定情況下可能無法滿足這個(gè)條件。

          我的建議是,不管怎樣都要考慮每種解決方案的優(yōu)缺點(diǎn),以及需要執(zhí)行哪種查詢。

          如果需要基于大量數(shù)據(jù)做查詢操作,Rick James 的文章提供了更深入的指導(dǎo)。

          http://mysql.rjweb.org/doc.php/lists

          如果我們的表沒有主鍵,比如是具有多對多關(guān)系的表,那么就使用傳統(tǒng)的 OFFSET/LIMIT 方式,只是這樣做存在潛在的慢查詢問題。我建議在需要分頁的表中使用自動遞增的主鍵,即使只是為了分頁。

          來源:toutiao.com/i6860655404431442444

          程序汪資料鏈接

          程序汪接的7個(gè)私活都在這里,經(jīng)驗(yàn)整理

          Java項(xiàng)目分享  最新整理全集,找項(xiàng)目不累啦 07版

          堪稱神級的Spring Boot手冊,從基礎(chǔ)入門到實(shí)戰(zhàn)進(jìn)階

          臥槽!字節(jié)跳動《算法中文手冊》火了,完整版 PDF 開放下載!

          臥槽!阿里大佬總結(jié)的《圖解Java》火了,完整版PDF開放下載!

          字節(jié)跳動總結(jié)的設(shè)計(jì)模式 PDF 火了,完整版開放下載!


          歡迎添加程序汪個(gè)人微信 itwang009  進(jìn)粉絲群或圍觀朋友圈

          瀏覽 47
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  精品成人Av一区二区三区 | 激情床上戏软件网站 | 超碰福利在线 | 狠狠狠狠狠狠狠操 | 麻豆传媒兔子先生 |