一般來說,在很多大廠中,需要做分表的時候,分表的數量都會選擇2的冪,比如16、64、128、512、1024等,這麼做有什麼好處呢?
首先,如果你看過 HashMap 的 hash 演算法的話,應該知道,HashMap 的容量其實也是2的冪,這麼做的好處在下面的文章中講過,那就是可以講取模操作改為更加高效的位運算。
因為,hash % 8 相當於 hash & (8-1),所以對於分8個表,可以使用雜湊值與7進行按位與操作,這不僅簡化了計算,還提升了效能。
所以,使用2的冪作為分表數量的第一個好處,就是可以將取模演算法最佳化成位運算演算法。
除了這個好處以外,我們通常分表都是伴隨著分庫的,比如我們分16個庫128張表, 這樣如果我們的分表數量和分庫數量都是2的冪,那麼就可以實現均勻分佈。128張表就可以均勻的分到16個庫中,每個庫中有8張表。
所以,使用2的冪作為分表數量的第二個好處,就是可以使得多張分表在多個庫中均勻分配。
當我們在做分庫分表的時候,必然要考慮的一個問題那就是二次分表的問題,比如我們根據當前的業務發展,計算出可能需要分4張表就夠了,但是隨著業務增長,可能認為需要更多表才行,這時候如果我們把新的分表數量定位8張表,那麼在做資料遷移的時候,就可以只遷移部分資料。
假設我們最開始將訂單表分成了4張表,分別是 order_00、order_01、order_02、order_03,這時候假設我們的分表演算法是根據 userId取模。即 userId % 4
order_00:userId % 4 == 0 order_01:userId % 4 == 1 order_02:userId % 4 == 2 order_03:userId % 4 == 3
當資料量增長,需要將表擴充套件到8個時,需要將演算法改為userId % 8 :
新的雜湊值計算:
order_00:userId % 8 == 0 order_01:userId % 8 == 1 order_02:userId % 8 == 2 order_03:userId % 8 == 3 order_04:userId % 8 == 4 order_05:userId % 8 == 5 order_06:userId % 8 == 6 order_07:userId % 8 == 7
而在做儲量資料遷移的時候,我們只需要重新分配那些原來在表0、1、2、3中,且雜湊值滿足 userId % 8 >= 4 的資料進行遷移就好了,userId % 8 的結果在0-3範圍內的資料其實是不用動的。
從表0遷移到表4:如果 hash % 8 == 4 從表1遷移到表5:如果 hash % 8 == 5 從表2遷移到表6:如果 hash % 8 == 6 從表3遷移到表7:如果 hash % 8 == 7
也就是說,從4張表擴容到8張表其實只需要遷移一半的資料。而如果不是2的冪,比如說從5張表擴容成9張表,那每個原資料都需要重新計算雜湊值並重新分配到新的表中。因為擴充套件後的表數量不是2的冪次,大多數資料都會被重新分配到不同的表中。
所以,使用2的冪作為分表數量的第三個好處,也是最重要的一個好處,那就是在做資料遷移時只需重新計算和遷移一半資料。這種方法不僅降低了系統擴充套件的複雜性,還減少了擴充套件過程中對系統性能的影響。