<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>

          深度分頁,我都是這么玩的

          共 2132字,需瀏覽 5分鐘

           ·

          2022-02-17 20:31

          點擊上方藍字“設為星標”





          大家好,我是架構擺渡人。這是實踐經(jīng)驗系列的第十一篇文章,這個系列會給大家分享很多在實際工作中有用的經(jīng)驗,如果有收獲,還請分享給更多的朋友。
          ?
          分頁查詢,無論是在B端的系統(tǒng),還是C端的應用,都有著廣泛的應用。只不過是應用方式和對性能的要求不一樣而已。
          ?
          在B端的系統(tǒng)中一般都是一個列表,下面有一個分頁的組件,可以選擇第幾頁的數(shù)據(jù),可以進行上下分頁,這種就是最常見的分頁方式,對應到數(shù)據(jù)庫中我們常實現(xiàn)的方式就是limit 0,10這種。
          ?
          在C端的應用中,也有分頁查詢的場景,但是對應性能要求比較高,我們都知道傳統(tǒng)limit在頁數(shù)越大的時候,性能也越差,主要是跳過的數(shù)據(jù)越多,回表的次數(shù)也多,這些時間都浪費了。所以一般都不會在C端應用中使用傳統(tǒng)的分頁方式。
          ?
          其次C端應用的分頁都是沒有分頁組件的,以訂單列表來說,是個分頁查詢的場景,在APP中是滑動下拉加載分頁。
          ?
          為了提高性能,一般會采用ID直接定位的方式來做分頁,改寫SQL如下:

          ?

          select * from table where id < #{lastId} order by id desc limit #{limit}

          ?

          改寫之后,就能根據(jù)上次返回的ID直接通過聚簇索引定位,然后取出對應的條數(shù)即可。
          ?
          這樣改完之后,無論用戶滑到多少頁,性能都是很快的。但是這種方式也會存在一個問題,就是你的主鍵ID必須是自增有序才行。可能有同學會問:還有無序的主鍵ID嗎?
          ?
          肯定是有的,假設你們業(yè)務發(fā)展很快,需要考慮整個機房不能提供服務的場景,這個時候就需要做異地多活了。
          ?
          在多活場景下,如果是單元庫,會進行雙向復制,此時主鍵ID如果都是自增的就會存在沖突問題。當然可以通過設置不同機房不同的自增步長來解決,這種方式不太靈活,當后面擴機房的時候又需要調(diào)整。
          ?
          另一種方式就是接入分布式ID,分布式ID一般的解決方案有snowflake,segment等。但在分布式場景下要提供完全遞增有序的很難,所以上面的分頁也會存在一定的問題。比如訂單列表,用戶下完單后去列表查看,很有可能最新的訂單不在第一條,因為你的ID不是全局遞增。
          ?
          這樣的問題我們?nèi)绾谓鉀Q呢?大家想想,在現(xiàn)實生活中什么是遞增的呢?答案就是時間
          ?
          所以,我們可以在表中單獨加個時間字段來保證有序性。這個時間的精度一定要高,比如微妙,納秒級別,這樣的高精度才能防止重復。還得建一個唯一索引來保證唯一性,確保萬無一失。
          ?
          有了這個時間字段,程序就不要去賦值了,直接使用數(shù)據(jù)庫的默認值,當然批量插入需要注意,因為批量插入的時間會一樣,所以程序中要禁止批量插入。
          ?
          假設時間字段有重復的,會對分頁造成影響嗎?肯定有影響的,我們舉個例子看下就知道了。

          ?

          4     2022-01-01 12:12:12.1114313     2022-01-01 12:12:12.1114312     2022-01-01 12:12:10.1114311     2022-01-01 12:12:09.111431

          ?

          我們的SQL如下:

          ?

          select * from table order by time desc limit 1

          ?

          那么第一頁的時候是沒有l(wèi)astTime值的,所以在拼接SQL的地方要做判斷。第一頁查出的數(shù)據(jù)是ID為1,時間為2022-01-01 12:12:12.111431的數(shù)據(jù)。
          ?
          第二頁的SQL如下:
          select * from table where time < '2022-01-01 12:12:12.111431' order by time desc limit 1

          ?

          獲取的結果是ID為3,時間為2022-01-01 12:12:10.111431的數(shù)據(jù),你會發(fā)現(xiàn)ID為2的數(shù)據(jù)丟失了,因為它的時間跟第一條一模一樣,這就是問題所在,所以我們要保證時間字段的唯一性。
          ?
          如果非得要通過SQL解決也是可以的,我們可以將查詢的SQL改寫下,如下:

          ?

          select * from table where time < '2022-01-01 12:12:12.111431' or (time='2022-01-01 12:12:12.111431' and id < 4) order by time desc,id desc limit 1

          ?

          通過加入or條件匹配最后一個時間,如果時間又相同的就會符合條件,并且這條數(shù)據(jù)的時間是小于之前最后一條數(shù)據(jù)的ID, 這樣就可以把重復的數(shù)據(jù)查出來了。
          ?
          需要注意的是之前我們返回給客戶端只需要最后一條數(shù)據(jù)的ID, 那么現(xiàn)在就要返回ID+時間了。

          ?

          大家好,我是從古代穿越過來的美男子:架構擺渡人。我將把我的武功秘籍全部傳授與你們,覺得有用請分享給身邊的朋友。來個三連吧,感謝各位!另外我還在B站錄制《真實訂單業(yè)務,億級數(shù)據(jù)帶你實戰(zhàn)分庫分表》的實戰(zhàn)課程,記得去學習哦!

          瀏覽 50
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  青娱视频日韩精品 | 豆花视频免费在线 | 又滑黄又爽的软件免费版 | 亚洲潮喷 | 久久久久国产豆花视频 |