回覆列表
  • 1 # 會技術的葛大爺

    在現在的網際網路架構中,分庫分表是一種非常常見的手段,主要用於解決單表或者單庫資料過多而導致的效能問題。

    通常,我們分庫有水平切分和垂直切分兩種方式

    垂直切分在我們的微服務架構中很常見,將資料庫根據業務模組進行拆分,業務的邏輯處理都透過服務呼叫來進行,而不是將邏輯放在資料層面,這樣就能降低資料庫表與表之間的耦合度。

    而水平切分,就是我們通常用來解決資料問題的手段了。將資料庫中單表的資料進行切分,分成多張相同的表單,資料按照一定的規則分佈到不同的資料庫例項中,從而達到降低資料量、提高效能的目的。

    而水平切分,就需要有分庫的依據

    使用哪個欄位來作為分庫的依據呢?

    通常情況下,我們會選擇主鍵作為分庫的依據,根據一定的演算法,將資料均勻的分佈到每個資料庫例項中,同時,儘量讓請求也均勻的分佈到每個資料庫例項上。

    例如:我們將訂單表進行了切分,一分為二(DB1、BD2),訂單表的主鍵就是訂單ID,我們想要均勻的分佈資料的話,我們可以對訂單ID進行判斷,是單數,我們就放在DB1中,是雙數,我們就放到DB2中,這樣,我們的資料分佈就非常的平均,同時,我們的請求在機率上,也是平均的。

    當然,分庫依據可以很多,這個可以根據自己的業務場景進行設定,只要明白,我們分庫是為了緩解資料庫的壓力,降低單表的資料量,如果我們分庫以後,DB1的資料量和請求數遠大於DB2,那麼我們分庫的意義就不是很大了。

    而分庫以後,最難解決的就是分頁查詢的問題

    通常情況下,我們的分頁查詢都是透過時間維度進行排序的。如以下sql:

    select * from T order by time offset X limit Y;

    但是,分庫以後,不同的資料庫如何進行查詢排序呢?我們就來說一跨庫的分頁查詢方式。

    全域性視野方式

    假設,我們現在要查詢某張表的第三頁資料,每頁100條資料,曾經沒有分庫的時候,我們只需要

    select * from T order by time offset 200 limit 100;

    但是,分庫以後,這第三頁的100條資料就有很多種分佈方式了。

    1)均勻分佈(極端情況)

    資料非常均勻的分佈在兩個庫中,想要找到第三頁的資料,就在兩個庫中各取50%就好了。

    2)全部來自一個庫(極端情況)

    資料非常不平均的分配到了一個庫中,所有的資料都來至於一個庫,也就是說,只需要取這個單庫的資料就可以了。

    3)散亂分佈(通常情況)

    這種情況下,我們很難知道,第三頁的資料應該在不同的庫中從第幾條開始取數,因為分庫後,我們丟失了全域性視野。因此,如果我們想要精準的找到目標資料,就必須重新構建全域性的視野。

    如何重新構建這種全域性視野呢?

    還是用我們要查詢第三頁的資料來舉例,我們可以將兩個庫中的第一到第三頁的資料全部查詢出來,然後在記憶體中合併後進行排序,再取出第三頁的資料。

    我們的sql也就發生了變化,從

    select * from T order by time offset 200 limit 100;

    改為

    select * from T order by time offset 0 limit 100+200;

    全域性視野方式進行查詢的好處很明顯,就是能夠讓業務資料絕對精準的返回。但是缺點也是明顯,資料的查詢量大,而且消耗的記憶體資源較多,當頁碼增大的時候,效能會集聚的下降。

    如果想要解決全域性視野方式的缺點,我們可以做出互動上的一點小犧牲來實現

    禁止跳轉頁方式

    相信這個分頁方式大家都不陌生,但是,這種分頁方式確實讓我們分庫以後的查詢難度幾何級的提升,如果想要解決跨頁查詢的問題,我們可以對我們的分頁控制元件進行最佳化,只保留“上一下”、“下一頁”的功能,去掉跳轉頁的功能。

    當禁止跳頁以後,我們每次查詢後,就能夠得到當頁最後一次查詢結果的時間,我們要查詢一個分頁中的記錄時,是需要查詢大於當前時間的100條記錄就可以了。

    兩個資料庫中各取100條,然後再彙總排序,這樣就能夠大大的提升查詢的效率,同時也保證了資料的精準。

    我們的sql也就改成了

    select * from T order by time where time>@preMaxTime limit 100;

    使用此方式,我們就不會因為頁碼增加而出現效能的下降了,只是使用者的互動體驗會稍差一些了。當然,如果是APP使用者,就不用擔心這點了,因為APP使用者很少使用跳轉頁的互動方式。

    允許精度損失方式

    允許精度損失的方式就比較暴力,我們不去管資料的分佈問題,只是單純的每個庫中取出50條資料,然後排序展示。

    在業務中,可能會出現第二頁的部分資料時間上早於第一頁的資料,這主要還是根據我們的儲存資料時候分分佈情況來決定。如果我們儲存資料的時候,分佈得越平均,這種查詢方式得到的結果自然就越精準。

    使用這種方式,我們就不需要考慮效能上的問題,也不需要考慮頁面跳轉和頁碼的問題,查詢的複雜度是最低的,是比較推薦的一種查詢方式。

    當然,如果你的業務不允許這樣的情況出現,還需要滿足互動、效率等等各種需求,那麼,就只有使用最後一個方式了。

    二次查詢方式

    這可以說是解決分庫查詢的究極武器了,能夠保證資料的精準度、查詢的效率、使用者的互動頁面,犧牲的只是小小的效能開銷和一些程式碼難度的上升。

    方式其實也不難,假設我們要查詢第21頁的資料,每頁5條。這個時候,我們先假設資料是平均分佈的,但是我們在每個庫都查詢全量的5條資料。也就是:

    select * from T order by time offset 100 limit 5;

    這時,我們得到的資料可能是這樣的。

    而兩個DB中,最小的時間是1487500001【minTime】,這個時間記錄下來。兩個DB中各自的最大時間也記錄下來,分別是DB1:1487500041【maxTime1】 和 DB2:1487500061【maxTime2】。

    這時,我們在使用時間去兩個資料庫中再次進行查詢。

    select * from T where time between minTime and maxTime1 order by time;select * from T where time between minTime and maxTime2 order by time;

    由於之前minTime來自於DB1,因此,DB1的資料不會發生變化,但是DB2中的條件被放寬了,因此可能會查詢出更多的資料。結果可能如下:

    而兩個結果集合並以後,相當於就獲得了全域性視野,也就可以很容易的找出這一頁需要的5條資料了。

  • 中秋節和大豐收的關聯?
  • 如何登入mysql?cmd怎麼連線mysql資料庫?