數據庫分庫分表

1、什麼是分庫分表?

分庫分表就是按照必定的規則,對原有的數據庫和表進行拆分,把本來存儲於一個庫的數據分塊存儲到多個庫上,把本來存儲到一個表的數據分塊存儲到多個表上。html

mysql中有一種機制是表鎖定和行鎖定,是爲了保證數據的完整性。表鎖定表示大家都不能對這張表進行操做,必須等我對錶操做完才行。行鎖定也同樣,別的sql必須等我對這條數據操做完了,才能對這條數據進行操做。mysql

2、爲何要分庫分表?

隨着時間和業務的發展,數據庫中的數據量增加是不可控的,庫和表中的數據會愈來愈大,隨之帶來的是更高的磁盤、IO、系統開銷,甚至性能上的瓶頸。而一臺服務器的資源終究是有限的。所以須要對數據庫和表進行拆分,從而更好地提供數據服務。算法

3、數據切分方式?

數據切分根據其切分類型,能夠分爲兩種方式:垂直(縱向)切分和水平(橫向)切分sql

一、垂直(縱向)切分

垂直切分常見有垂直分庫和垂直分表兩種。數據庫

垂直分庫就是根據業務耦合性,將關聯度低的不一樣表存儲在不一樣的數據庫。作法與大系統拆分爲多個小系統相似,按業務分類進行獨立劃分。與"微服務治理"的作法類似,每一個微服務使用單獨的一個數據庫。如圖:緩存

垂直分表是基於數據庫中的"列"進行,某個表字段較多,能夠新建一張擴展表,將不常常用或字段長度較大的字段拆分出去到擴展表中。在字段不少的狀況下(例如一個大表有100多個字段),經過"大表拆小表",更便於開發與維護,也能避免跨頁問題,MySQL底層是經過數據頁存儲的,一條記錄佔用空間過大會致使跨頁,形成額外的性能開銷。另外數據庫以行爲單位將數據加載到內存中,這樣表中字段長度較短且訪問頻率較高,內存能加載更多的數據,命中率更高,減小了磁盤IO,從而提高了數據庫性能。安全

垂直切分的優勢:服務器

  • 解決業務系統層面的耦合,業務清晰
  • 與微服務的治理相似,也能對不一樣業務的數據進行分級管理、維護、監控、擴展等
  • 高併發場景下,垂直切分必定程度的提高IO、數據庫鏈接數、單機硬件資源的瓶頸

缺點:網絡

  • 部分表沒法join,只能經過接口聚合方式解決,提高了開發的複雜度
  • 分佈式事務處理複雜
  • 依然存在單表數據量過大的問題(須要水平切分)

 

二、水平(橫向)切分

當一個應用難以再細粒度的垂直切分,或切分後數據量行數巨大,存在單庫讀寫、存儲性能瓶頸,這時候就須要進行水平切分了。併發

水平切分分爲庫內分表和分庫分表,是根據表內數據內在的邏輯關係,將同一個表按不一樣的條件分散到多個數據庫或多個表中,每一個表中只包含一部分數據,從而使得單個表的數據量變小,達到分佈式的效果。如圖所示: 

庫內分表只解決了單一表數據量過大的問題,但沒有將表分佈到不一樣機器的庫上,所以對於減輕MySQL數據庫的壓力來講,幫助不是很大,你們仍是競爭同一個物理機的CPU、內存、網絡IO,最好經過分庫分表來解決。

水平切分的優勢:

  • 不存在單庫數據量過大、高併發的性能瓶頸,提高系統穩定性和負載能力
  • 應用端改造較小,不須要拆分業務模塊

缺點:

  • 跨分片的事務一致性難以保證
  • 跨庫的join關聯查詢性能較差
  • 數據屢次擴展難度和維護量極大

水平切分後同一張表會出如今多個數據庫/表中,每一個庫/表的內容不一樣。幾種典型的數據分片規則爲:

一、根據數值範圍

按照時間區間或ID區間來切分。例如:按日期將不一樣月甚至是日的數據分散到不一樣的庫中;將userId爲1~9999的記錄分到第一個庫,10000~20000的分到第二個庫,以此類推。某種意義上,某些系統中使用的"冷熱數據分離",將一些使用較少的歷史數據遷移到其餘庫中,業務功能上只提供熱點數據的查詢,也是相似的實踐。

這樣的優勢在於:

  • 單表大小可控
  • 自然便於水平擴展,後期若是想對整個分片集羣擴容時,只須要添加節點便可,無需對其餘分片的數據進行遷移
  • 使用分片字段進行範圍查找時,連續分片可快速定位分片進行快速查詢,有效避免跨分片查詢的問題。

缺點:

  • 熱點數據成爲性能瓶頸。連續分片可能存在數據熱點,例如按時間字段分片,有些分片存儲最近時間段內的數據,可能會被頻繁的讀寫,而有些分片存儲的歷史數據,則不多被查詢

二、根據數值取模

通常採用hash取模mod的切分方式,例如:將 Customer 表根據 cusno 字段切分到4個庫中,餘數爲0的放到第一個庫,餘數爲1的放到第二個庫,以此類推。這樣同一個用戶的數據會分散到同一個庫中,若是查詢條件帶有cusno字段,則可明肯定位到相應庫去查詢。

優勢:

  • 數據分片相對比較均勻,不容易出現熱點和併發訪問的瓶頸

缺點:

  • 後期分片集羣擴容時,須要遷移舊的數據(使用一致性hash算法能較好的避免這個問題)
  • 容易面臨跨分片查詢的複雜問題。好比上例中,若是頻繁用到的查詢條件中不帶cusno時,將會致使沒法定位數據庫,從而須要同時向4個庫發起查詢,再在內存中合併數據,取最小集返回給應用,分庫反而成爲拖累。

三、垂直拆分和水平拆分的區別

數據水平拆分與數據垂直拆分的區別是,垂直拆分是把不一樣的表拆到不一樣的數據庫中,而水平拆分是把同一個表拆到不一樣的數據庫中。例如,通過垂直拆分後,用戶表與交易表、商品表不在一個數據庫中了,若是數據量或者更新量太大,咱們能夠進一步把用戶表拆分到兩個數據庫中,它們擁有結構如出一轍的用戶表,並且每一個庫中的用戶表都只涵蓋了一部分的用戶,兩個數據庫的用戶合在一塊兒就至關於沒有拆分以前的用戶表。

垂直(縱向)拆分:是指按功能模塊拆分,好比分爲訂單庫、商品庫、用戶庫...這種方式多個數據庫之間的表結構不一樣。

水平(橫向)拆分:將同一個表的數據進行分塊保存到不一樣的數據庫中,這些數據庫中的表結構徹底相同。

4、什麼時候分庫分表?

一、能不切分儘可能不要切分

並非全部表都須要進行切分,主要仍是看數據的增加速度。切分後會在某種程度上提高業務的複雜度,數據庫除了承載數據的存儲和查詢外,協助業務更好的實現需求也是其重要工做之一。

不到萬不得已不用輕易使用分庫分表這個大招,避免"過分設計"和"過早優化"。分庫分表以前,不要爲分而分,先盡力去作力所能及的事情,例如:升級硬件、升級網絡、讀寫分離、索引優化等等。當數據量達到單表的瓶頸時候,再考慮分庫分表。

二、數據量過大,正常運維影響業務訪問

這裏說的運維,指:

1)對數據庫備份,若是單表太大,備份時須要大量的磁盤IO和網絡IO。例如1T的數據,網絡傳輸佔50MB時候,須要20000秒才能傳輸完畢,整個過程的風險都是比較高的

2)對一個很大的表進行DDL修改時,MySQL會鎖住全表,這個時間會很長,這段時間業務不能訪問此表,影響很大。若是使用pt-online-schema-change,使用過程當中會建立觸發器和影子表,也須要很長的時間。在此操做過程當中,都算爲風險時間。將數據表拆分,總量減小,有助於下降這個風險。

3)大表會常常訪問與更新,就更有可能出現鎖等待。將數據切分,用空間換時間,變相下降訪問壓力

三、隨着業務發展,須要對某些字段垂直拆分

舉個例子,假如項目一開始設計的用戶表以下:

id                   bigint             #用戶的ID
name                 varchar            #用戶的名字
last_login_time      datetime           #最近登陸時間
personal_info        text               #私人信息
.....                                   #其餘信息字段

在項目初始階段,這種設計是知足簡單的業務需求的,也方便快速迭代開發。而當業務快速發展時,用戶量從10w激增到10億,用戶很是的活躍,每次登陸會更新 last_login_name 字段,使得 user 表被不斷update,壓力很大。而其餘字段:id, name, personal_info 是不變的或不多更新的,此時在業務角度,就要將 last_login_time 拆分出去,新建一個 user_time 表。

personal_info 屬性是更新和查詢頻率較低的,而且text字段佔據了太多的空間。這時候,就要對此垂直拆分出 user_ext 表了。

四、數據量快速增加

隨着業務的快速發展,單表中的數據量會持續增加,當性能接近瓶頸時,就須要考慮水平切分,作分庫分表了。此時必定要選擇合適的切分規則,提早預估好數據容量。

五、安全性和可用性

雞蛋不要放在一個籃子裏。在業務層面上垂直切分,將不相關的業務的數據庫分隔,由於每一個業務的數據量、訪問量都不一樣,不能由於一個業務把數據庫搞掛而牽連到其餘業務。利用水平切分,當一個數據庫出現問題時,不會影響到100%的用戶,每一個庫只承擔業務的一部分數據,這樣總體的可用性就能提升。

5、數據切分可能帶來的問題

分庫分表能有效的緩解單機和單庫帶來的性能瓶頸和壓力,突破網絡IO、硬件資源、鏈接數的瓶頸,同時也帶來了一些問題。下面將描述這些技術挑戰以及對應的解決思路。 

一、事務一致性問題

分佈式事務

當更新內容同時分佈在不一樣庫中,不可避免會帶來跨庫事務問題。跨分片事務也是分佈式事務,沒有簡單的方案,通常可以使用"XA協議"和"兩階段提交"處理。

分佈式事務能最大限度保證了數據庫操做的原子性。但在提交事務時須要協調多個節點,推後了提交事務的時間點,延長了事務的執行時間。致使事務在訪問共享資源時發生衝突或死鎖的機率增高。隨着數據庫節點的增多,這種趨勢會愈來愈嚴重,從而成爲系統在數據庫層面上水平擴展的枷鎖。

最終一致性

對於那些性能要求很高,但對一致性要求不高的系統,每每不苛求系統的實時一致性,只要在容許的時間段內達到最終一致性便可,可採用事務補償的方式。與事務在執行中發生錯誤後當即回滾的方式不一樣,事務補償是一種過後檢查補救的措施,一些常見的實現方法有:對數據進行對帳檢查,基於日誌進行對比,按期同標準數據來源進行同步等等。事務補償還要結合業務系統來考慮。

 

二、跨節點關聯查詢 join 問題

切分以前,系統中不少列表和詳情頁所需的數據能夠經過sql join來完成。而切分以後,數據可能分佈在不一樣的節點上,此時join帶來的問題就比較麻煩了,考慮到性能,儘可能避免使用join查詢。

解決這個問題的一些方法:

1)全局表

全局表,也可看作是"數據字典表",就是系統中全部模塊均可能依賴的一些表,爲了不跨庫join查詢,能夠將這類表在每一個數據庫中都保存一份。這些數據一般不多會進行修改,因此也不擔憂一致性的問題。

2)字段冗餘

一種典型的反範式設計,利用空間換時間,爲了性能而避免join查詢。例如:訂單表保存userId時候,也將userName冗餘保存一份,這樣查詢訂單詳情時就不須要再去查詢"買家user表"了。

但這種方法適用場景也有限,比較適用於依賴字段比較少的狀況。而冗餘字段的數據一致性也較難保證,就像上面訂單表的例子,買家修改了userName後,是否須要在歷史訂單中同步更新呢?這也要結合實際業務場景進行考慮。

3)數據組裝

在系統層面,分兩次查詢,第一次查詢的結果集中找出關聯數據id,而後根據id發起第二次請求獲得關聯數據。最後將得到到的數據進行字段拼裝。

4)ER分片

關係型數據庫中,若是能夠先肯定表之間的關聯關係,並將那些存在關聯關係的表記錄存放在同一個分片上,那麼就能較好的避免跨分片join問題。在1:1或1:n的狀況下,一般按照主表的ID主鍵切分。以下圖所示:

這樣一來,Data Node1上面的order訂單表與orderdetail訂單詳情表就能夠經過orderId進行局部的關聯查詢了,Data Node2上也同樣。

 

三、跨節點分頁、排序、函數問題

跨節點多庫進行查詢時,會出現limit分頁、order by排序等問題。分頁須要按照指定字段進行排序,當排序字段就是分片字段時,經過分片規則就比較容易定位到指定的分片;當排序字段非分片字段時,就變得比較複雜了。須要先在不一樣的分片節點中將數據進行排序並返回,而後將不一樣分片返回的結果集進行彙總和再次排序,最終返回給用戶。如圖所示:

上圖中只是取第一頁的數據,對性能影響還不是很大。可是若是取得頁數很大,狀況則變得複雜不少,由於各分片節點中的數據多是隨機的,爲了排序的準確性,須要將全部節點的前N頁數據都排序好作合併,最後再進行總體的排序,這樣的操做時很耗費CPU和內存資源的,因此頁數越大,系統的性能也會越差。

在使用Max、Min、Sum、Count之類的函數進行計算的時候,也須要先在每一個分片上執行相應的函數,而後將各個分片的結果集進行彙總和再次計算,最終將結果返回。如圖所示:

 

四、全局主鍵避重問題

在分庫分表環境中,因爲表中數據同時存在不一樣數據庫中,主鍵值平時使用的自增加將無用武之地,某個分區數據庫自生成的ID沒法保證全局惟一。所以須要單獨設計全局主鍵,以免跨庫主鍵重複問題。有一些常見的主鍵生成策略:

1)UUID

UUID標準形式包含32個16進制數字,分爲5段,形式爲8-4-4-4-12的36個字符,例如:550e8400-e29b-41d4-a716-446655440000

UUID是主鍵是最簡單的方案,本地生成,性能高,沒有網絡耗時。但缺點也很明顯,因爲UUID很是長,會佔用大量的存儲空間;另外,做爲主鍵創建索引和基於索引進行查詢時都會存在性能問題,在InnoDB下,UUID的無序性會引發數據位置頻繁變更,致使分頁。

2)結合數據庫維護主鍵ID表

在數據庫中創建 sequence 表:

複製代碼
CREATE TABLE `sequence` (  
  `id` bigint(20) unsigned NOT NULL auto_increment,  
  `stub` char(1) NOT NULL default '',  
  PRIMARY KEY  (`id`),  
  UNIQUE KEY `stub` (`stub`)  
) ENGINE=MyISAM;
複製代碼

stub字段設置爲惟一索引,同一stub值在sequence表中只有一條記錄,能夠同時爲多張表生成全局ID。sequence表的內容,以下所示:

+-------------------+------+  
| id                | stub |  
+-------------------+------+  
| 72157623227190423 |    a |  
+-------------------+------+  

使用 MyISAM 存儲引擎而不是 InnoDB,以獲取更高的性能。MyISAM使用的是表級別的鎖,對錶的讀寫是串行的,因此不用擔憂在併發時兩次讀取同一個ID值。

當須要全局惟一的64位ID時,執行:

REPLACE INTO sequence (stub) VALUES ('a');  
SELECT LAST_INSERT_ID();  

這兩條語句是Connection級別的,select last_insert_id() 必須與 replace into 在同一數據庫鏈接下才能獲得剛剛插入的新ID。

使用replace into代替insert into好處是避免了錶行數過大,不須要另外按期清理。

此方案較爲簡單,但缺點也明顯:存在單點問題,強依賴DB,當DB異常時,整個系統都不可用。配置主從能夠增長可用性,但當主庫掛了,主從切換時,數據一致性在特殊狀況下難以保證。另外性能瓶頸限制在單臺MySQL的讀寫性能。

flickr團隊使用的一種主鍵生成策略,與上面的sequence表方案相似,但更好的解決了單點和性能瓶頸的問題。

這一方案的總體思想是:創建2個以上的全局ID生成的服務器,每一個服務器上只部署一個數據庫,每一個庫有一張sequence表用於記錄當前全局ID。表中ID增加的步長是庫的數量,起始值依次錯開,這樣能將ID的生成散列到各個數據庫上。以下圖所示:

由兩個數據庫服務器生成ID,設置不一樣的auto_increment值。第一臺sequence的起始值爲1,每次步長增加2,另外一臺的sequence起始值爲2,每次步長增加也是2。結果第一臺生成的ID都是奇數(1, 3, 5, 7 ...),第二臺生成的ID都是偶數(2, 4, 6, 8 ...)。

這種方案將生成ID的壓力均勻分佈在兩臺機器上。同時提供了系統容錯,第一臺出現了錯誤,能夠自動切換到第二臺機器上獲取ID。但有如下幾個缺點:系統添加機器,水平擴展時較複雜;每次獲取ID都要讀寫一次DB,DB的壓力仍是很大,只能靠堆機器來提高性能。

能夠基於flickr的方案繼續優化,使用批量的方式下降數據庫的寫壓力,每次獲取一段區間的ID號段,用完以後再去數據庫獲取,能夠大大減輕數據庫的壓力。以下圖所示:

仍是使用兩臺DB保證可用性,數據庫中只存儲當前的最大ID。ID生成服務每次批量拉取6個ID,先將max_id修改成5,當應用訪問ID生成服務時,就不須要訪問數據庫,從號段緩存中依次派發0~5的ID。當這些ID發完後,再將max_id修改成11,下次就能派發6~11的ID。因而,數據庫的壓力下降爲原來的1/6。

3)Snowflake分佈式自增ID算法

Twitter的snowflake算法解決了分佈式系統生成全局ID的需求,生成64位的Long型數字,組成部分:

  • 第一位未使用
  • 接下來41位是毫秒級時間,41位的長度能夠表示69年的時間
  • 5位datacenterId,5位workerId。10位的長度最多支持部署1024個節點
  • 最後12位是毫秒內的計數,12位的計數順序號支持每一個節點每毫秒產生4096個ID序列

這樣的好處是:毫秒數在高位,生成的ID總體上按時間趨勢遞增;不依賴第三方系統,穩定性和效率較高,理論上QPS約爲409.6w/s(1000*2^12),而且整個分佈式系統內不會產生ID碰撞;可根據自身業務靈活分配bit位。

不足就在於:強依賴機器時鐘,若是時鐘回撥,則可能致使生成ID重複。

綜上

結合數據庫和snowflake的惟一ID方案,能夠參考業界較爲成熟的解法:Leaf——美團點評分佈式ID生成系統,並考慮到了高可用、容災、分佈式下時鐘等問題。

 

五、數據遷移、擴容問題

當業務高速發展,面臨性能和存儲的瓶頸時,纔會考慮分片設計,此時就不可避免的須要考慮歷史數據遷移的問題。通常作法是先讀出歷史數據,而後按指定的分片規則再將數據寫入到各個分片節點中。此外還須要根據當前的數據量和QPS,以及業務發展的速度,進行容量規劃,推算出大概須要多少分片(通常建議單個分片上的單表數據量不超過1000W)

若是採用數值範圍分片,只須要添加節點就能夠進行擴容了,不須要對分片數據遷移。若是採用的是數值取模分片,則考慮後期的擴容問題就相對比較麻煩。

 6、使用Merge存儲引擎實現MySQL分表(水平切分)

1、使用場景

  Merge表有點相似於視圖。使用Merge存儲引擎實現MySQL分表,這種方法比較適合那些沒有事先考慮分表,隨着數據的增多,已經出現了數據查詢慢的狀況。這個時候若是要把已有的大數據量表分開比較痛苦,最痛苦的事就是改代碼。因此使用Merge存儲引擎實現MySQL分表能夠避免改代碼。

  Merge引擎下每一張表只有一個MRG文件。MRG裏面存放着分表的關係,以及插入數據的方式。它就像是一個外殼,或者是鏈接池,數據存放在分表裏面。

  merge合併表的要求:

  • 合併的表使用的必須是MyISAM引擎
  • 表的結構必須一致,包括索引、字段類型、引擎和字符集

  對於增刪改查,直接操做總表便可。

2、建表

  1.用戶1表

複製代碼
CREATE TABLE `user1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `sex` int(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 
複製代碼

  2.用戶2表

  create table user2 like user1;

  3.主表

複製代碼
CREATE TABLE `alluser` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `sex` int(1) NOT NULL DEFAULT '0',
  KEY `id` (`id`)
) ENGINE=MRG_MyISAM DEFAULT CHARSET=utf8 INSERT_METHOD=LAST UNION=(`user1`,`user2`);
複製代碼

  1) ENGINE = MERGE 和 ENGINE = MRG_MyISAM是同樣的意思,都是表明使用的存儲引擎是 Merge。

  2) INSERT_METHOD,表示插入方式,取值能夠是:0 和 1,0表明不容許插入,1表明能夠插入;

  3) FIRST插入到UNION中的第一個表,LAST插入到UNION中的最後一個表。

3、操做

  1. 先在user1表中增長一條數據,而後再在user2表中增長一條數據,查看 alluser中的數據。

   insert into user1(name,sex) values ('張三',1);

   insert into user2(name,sex) values ('李四',2);

    select * from alluser;  發現是剛剛插入的數據以下:

   

     這就出現了一個id重複,這就形成了當刪除和修改的時候異常,解決辦法是給 alluser的id賦惟一值。

     咱們解決方法是,從新創建一張表tb_ids(id int),用來專門存一個id的,並插入一條初始數據,同時刪除掉user1和user2中的數據。

  create table tb_ids(id int);
  insert into tb_ids values(1);
  delete from user1;
  delete from user2;

   而後在user1和user2表中分別創建一個觸發器(tr_seq和tr_seq2),觸發器的功能是 當在user1或者user2表中增長一條記錄時,取出tb_ids中的id值,賦給user1和user2的id,而後將tb_ids的id值加1,

   user1表的觸發器內容以下(user2表的觸發器修要修改 觸發器的名字 和 表名,以下紅字標註):   

複製代碼
   DELIMITER $$
   CREATE TRIGGER tr_seq
   BEFORE INSERT on user1
   FOR EACH ROW BEGIN 
      select id  into @testid from tb_ids limit 1;
      update tb_ids set id = @testid + 1;
   set new.id =  @testid;
   END$$
   DELIMITER;
複製代碼

  2.在user1和user2表中分別增長一條數據,

    insert into user1(name,sex) values('王五',1);

    insert into user2(name,sex) values('趙六',2);

  3.查詢user1和user2中的數據:

               

  4.查詢總表alluser中的數據,發現id沒有重複的:

   

      搞定。

7、垂直切分的依據

當一個表屬性不少時,如何來進行垂直拆分呢?若是沒有特殊狀況,拆分依據主要有幾點:

(1)將長度較短,訪問頻率較高的屬性儘可能放在一個表裏,這個表暫且稱爲主表

(2)將字段較長,訪問頻率較低的屬性儘可能放在一個表裏,這個表暫且稱爲擴展表

若是1和2都知足,還能夠考慮第三點:

(3)常常一塊兒訪問的屬性,也能夠放在一個表裏

優先考慮1和2,第3點不是必須。另,若是實在屬性過多,主表和擴展表均可以有多個。

 

通常來講,數據量併發量比較大時,數據庫的上層都會有一個服務層。須要注意的是,當應用方須要同時訪問主表和擴展表中的屬性時,服務層不要使用join來連表訪問,而應該分兩次進行查詢:


緣由是,大數據高併發互聯網場景下,通常來講,吞吐量和擴展性是主要矛盾:

(1)join更消損耗數據庫性能

(2)join會讓base表和ext表耦合在一塊兒(必須在一個數據庫實例上),不利於數據量大時拆分到不一樣的數據庫實例上(機器上)。畢竟減小數據量,提高性能纔是垂直拆分的初衷。

爲何要這麼這麼拆分?

爲什麼要將字段短,訪問頻率高的屬性放到一個表內?爲什麼這麼垂直拆分能夠提高性能?由於:

(1)數據庫有本身的內存buffer,會將磁盤上的數據load到內存buffer裏(暫且理解爲進程內緩存吧)

(2)內存buffer緩存數據是以row爲單位的

(3)在內存有限的狀況下,在數據庫內存buffer裏緩存短row,就能緩存更多的數據

(4)在數據庫內存buffer裏緩存訪問頻率高的row,就能提高緩存命中率,減小磁盤的訪問

 

舉個例子就很好理解了:

假設數據庫內存buffer爲1G,未拆分的user表1行數據大小爲1k,那麼只能緩存100w行數據。

若是垂直拆分紅user_base和user_ext,其中:

(1)user_base訪問頻率高(例如uid, name, passwd, 以及一些flag等),一行大小爲0.1k

(2)user_ext訪問頻率低(例如簽名, 我的介紹等),一行大小爲0.9k

那邊內存buffer就就能緩存近乎1000w行user_base的記錄,訪問磁盤的機率會大大下降,數據庫訪問的時延會大大下降,吞吐量會大大增長。

 

如何聯合查找?

分庫分表的結果會使數據分散,很差查詢,主要有兩種查詢方式:

(1)分步查:先查找主表,而後獲得關聯表的id,再發起請求獲得關聯數據;

(2)聯合查:同時發起多個查詢請求,而後將全部的結果集合起來。

 

總結

(1)水平拆分和垂直拆分都是下降數據量大小,提高數據庫性能的常見手段

(2)流量大,數據量大時,數據訪問要有service層,而且service層不要經過join來獲取主表和擴展表的屬性

(3)垂直拆分的依據,儘可能把長度較短,訪問頻率較高的屬性放在主表裏

8、參考

一、https://www.jianshu.com/p/3fed6db29a01

二、https://www.cnblogs.com/butterfly100/p/9034281.html

三、https://blog.csdn.net/cfy1024/article/details/80899189

四、https://www.cnblogs.com/sunny3096/p/8595058.html

五、https://www.cnblogs.com/xbq8080/p/6628034.html

六、https://blog.csdn.net/wufaliang003/article/details/78619266

相關文章
相關標籤/搜索