本文轉自:https://baijiahao.baidu.com/s?id=1627688882923429891&wfr=spider&for=pcmysql
當一張表的數據達到幾千萬時,查詢一次所花的時間會變長。這時候,若是有聯合查詢的話,可能會卡死在那兒,甚至把系統給拖垮。算法
而分庫分表的目的就在於此:減少數據庫的負擔,提升數據庫的效率,縮短查詢時間。另外,由於分庫分表這種改造是可控的,底層仍是基於RDBMS,所以整個數據庫的運維體系以及相關基礎設施都是可重用的。sql
目前咱們系統將近20億數據,每張表最大的接近600w條/表,每條數據大約3k,每一個表將近1.5G的數據。查詢常常超時,單條SQL執行count(*)查詢時間達到了最大260ms,0.26s(標準是超過0.1s的數據爲慢SQL)。數據庫
爲了說明咱們爲何要分庫分表,咱們看一下sql的執行過程。服務器
mysql執行一條sql的過程以下:運維
一、收到sql數據庫設計
二、把sql放到排隊隊列中分佈式
三、執行sqlide
四、返回結果性能
在這個執行過程當中最花時間的地方在於:
1.排隊等待的時間,
2.sql的執行時間。
若是有2個sql都要同時修改同一張表的同一條數據,mysql對這種狀況的處理是:一種是表鎖定(MyISAM存儲引擎),一個是行鎖定(InnoDB存儲引擎)。
表鎖定表示其餘操做都不能對這張表進行操做,必須等當前對錶的操做完才行。行鎖定也同樣,別的sql必須等這條數據操做完了,其餘人才能對這條數據進行操做。
若是數據太多,一次執行的時間太長,等待的時間就越長,這也是咱們爲何要分表的緣由。
分庫分表術語:
讀寫分離: 不一樣的數據庫,同步相同的數據,分別只負責數據的讀和寫;
分區:指定分區列表達式,把記錄拆分到不一樣的區域中(必須是同一服務器,能夠是不一樣硬盤),應用看來仍是同一張表,沒有變化;
分庫:一個系統的多張數據表,存儲到多個數據庫實例中;
分表: 對於一張多行(記錄)多列(字段)的二維數據表,又分兩種情形:
垂直分表: 豎向切分,不一樣分表存儲不一樣的字段,能夠把不經常使用或者大容量、或者不一樣業務的字段拆分出去;水平分表(最複雜): 橫向切分,按照特定分片算法,不一樣分表存儲不一樣的記錄。在實際生產中,一般的進化過程是:單庫單表->單庫多表->多庫多表;;分區->分表->分庫(垂直分庫 - 水平分庫 - 讀寫分離)
單庫單表
單庫單表是最多見的數據庫設計,例如,有一張訂單表(order)放在數據庫中,全部的訂單均可以在order表中查到。
單庫多表
隨着訂單數量的增長,order表的數據量會愈來愈大,當數據量達到必定程度的時候,對order表的查詢會變慢,從而影響整個DB的性能。
另外,隨着需求的迭代,若是增長添加一列的時候,mysql會鎖表,期間全部的讀寫操做只能等待,別無他法。
這時候,能夠將order進行水平的切分,產生多個表結構徹底同樣的order表。好比:order_01,order_02....,order_n,那麼order_01+order_02+order_n的數據是一份完整的訂單數據。
這個水平切分,簡單的作法如:
按數量切分,1~1000的存在第一張表,1001~2000存在第二張表;
按時間切分,好比:2019年1月份存在第一張表,2019年2月份存在第二張表;還能夠按照id的哈希值進行切分,等等等等
多庫多表
隨着數據量增長,單臺數據庫的硬件存儲不夠了,而且,隨着查詢量的增長,單臺數據庫服務器已經沒辦法支撐。這時候就須要對數據庫進行水平區分。
好比按地區分庫,一個省份在一個物理數據庫等等
任何事情都有兩面性,分庫分表也不例外,若是採用分庫分表,會引入新的的問題
1.分佈式事務問題
作了垂直分庫或者水平分庫之後,就必然會涉及到跨庫執行SQL的問題,就會引起互聯網界的老大難問題-"分佈式事務"。那麼要如何解決這個問題呢?
使用分佈式事務中間件使用MySQL自帶的針對跨庫的事務一致性方案(XA),不過性能要比單庫的慢10倍左右。可否避免掉跨庫操做(好比將用戶和商品放在同一個庫中)2.跨庫join的問題
分庫分表後,表之間的關聯操做將受到限制,就沒法join位於不一樣分庫的表,也沒法join分表粒度不一樣的表, 結果本來一次查詢可以完成的業務,可能須要屢次查詢才能完成。
那麼要如何解決這個問題呢?
簡單的解決方法:
全局表:基礎數據,全部庫都拷貝一份。字段冗餘:把須要join的字段冗餘在各個表中,這樣有些字段就不用join去查詢了。系統層組裝:應用端先分別查詢出全部複覈條件的,而後在應用端組裝起來,相似於一個mapreduce的過程(較複雜)。3.橫向擴容的問題
當咱們使用哈希取模作分表的時候,針對數據量的遞增,可能須要動態的增長表,此時就須要考慮數據遷移的問題。
原來使用的是hash後對8進行取模,那麼,數據是均分在8個表(庫)上。
若是8個表不夠的時候,咱們要擴展到16個表,這時候,咱們hash後對16取模,新數據是沒有問題的,舊數據就會發生錯亂。
若是哈希後是9,那麼,原來咱們對8取模後,是1,會到表1進行查詢;可是,如今咱們是對16取模,那麼是到表9進行查詢的,而這個數據在表9又不存在,所以,就會找不到數據了
4.結果集合並、排序的問題
由於咱們是將數據分散存儲到不一樣的庫、表裏的,當咱們查詢指定數據列表時,數據來源於不一樣的子庫或者子表,就必然會引起結果集合並、排序的問題。
若是每次查詢都須要排序、合併等操做,性能確定會受很是大的影響。
上面列出了分庫分表的常見的一些,總的來講:
能不切分儘可能不要切分,若是沒有達到幾百萬,一般無需分庫分表若是必定要切分,必定要選擇合適的切分規則,提早規劃好。若是必定要切分,儘可能經過數據冗餘或表分組來下降跨庫 Join 的可能。對於如今市面上有好幾種數據庫中間件,這些中間件對數據 Join 實現,箇中滋味,只能本身體會。業務讀取儘可能少使用多表 Join。數據儘量的比較均勻分佈數據到各個節點上