分庫分表詳解


分庫分表是什么

下邊以電商系統中的例子來說明,下圖是電商系統賣家模塊的表結構:
在這里插入圖片描述
通過以下SQL能夠獲取到商品相關的店鋪信息、地理區域信息:

SELECT p.*,r.[地理區域名稱],s.[店鋪名稱],s.[信譽]
FROM [商品信息] p 
LEFT JOIN [地理區域] r ON p.[產地] = r.[地理區域編碼]
LEFT JOIN [店鋪信息] s ON p.id = s.[所屬店鋪]
WHERE p.id = ?

隨着公司業務快速發展,數據庫中的數據量猛增,訪問性能也變慢了,優化迫在眉睫。分析一下問題出現在哪兒呢? 關系型數據庫本身比較容易成為系統瓶頸,單機存儲容量、連接數、處理能力都有限。當單表的數據量達到1000W或100G以后,由於查詢維度較多,即使添加從庫、優化索引,做很多操作時性能仍下降嚴重。

方案1:

通過提升服務器硬件能力來提高數據處理能力,比如增加存儲容量 、CPU等,這種方案成本很高,並且如果瓶頸在MySQL本身那么提高硬件也是有很的。

方案2:

把數據分散在不同的數據庫中,使得單一數據庫的數據量變小來緩解單一數據庫的性能問題,從而達到提升數據庫性能的目的,如下圖:將電商數據庫拆分為若干獨立的數據庫,並且對於大表也拆分為若干小表,通過這種數據庫拆分的方法來解決數據庫的性能問題。
在這里插入圖片描述
分庫分表就是為了解決由於數據量過大而導致數據庫性能降低的問題,將原來獨立的數據庫拆分成若干數據庫組成 ,將數據大表拆分成若干數據表組成,使得單一數據庫、單一數據表的數據量變小,從而達到提升數據庫性能的目的。

垂直分表

分庫分表包括分庫和分表兩個部分,在生產中通常包括:垂直分庫、水平分庫、垂直分表、水平分表四種方式。
先說 垂直分表:
通常在商品列表中是不顯示商品詳情信息的,如下圖:
在這里插入圖片描述
用戶在瀏覽商品列表時,只有對某商品感興趣時才會查看該商品的詳細描述。因此,商品信息中商品描述字段訪問頻次較低,且該字段存儲占用空間較大,訪問單個數據IO時間較長;商品信息中商品名稱、商品圖片、商品價格等其他字段數據訪問頻次較高。

由於這兩種數據的特性不一樣,因此他考慮將商品信息表拆分如下:

將訪問頻次低的商品描述信息單獨存放在一張表中,訪問頻次較高的商品基本信息單獨放在一張表中。
在這里插入圖片描述
商品列表可采用以下sql:

SELECT p.*,r.[地理區域名稱],s.[店鋪名稱],s.[信譽]
FROM [商品信息] p 
LEFT JOIN [地理區域] r ON p.[產地] = r.[地理區域編碼]
LEFT JOIN [店鋪信息] s ON p.id = s.[所屬店鋪]
WHERE...ORDER BY...LIMIT...

 

需要獲取商品描述時,再通過以下sql獲取:

SELECT *
FROM [商品描述] 
WHERE [商品ID] = ?

 

垂直分表定義:將一個表按照字段分成多表,每個表存儲其中一部分字段。
它帶來的提升是:

1.為了避免IO爭搶並減少鎖表的幾率,查看詳情的用戶與商品信息瀏覽互不影響

2.充分發揮熱門數據的操作效率,商品信息的操作的高效率不會被商品描述的低效率所拖累。

為什么大字段IO效率低:第一是由於數據量本身大,需要更長的讀取時間;第二是跨頁,頁是數據庫存儲單位,很多查找及定位操作都是以頁為單位,單頁內的數據行越多數據庫整體性能越好,而大字段占用空間大,單頁內存儲行數少,因此IO效率較低。第三,數據庫以行為單位將數據加載到內存中,這樣表中字段長度較短且訪問頻率較高,內存能加載更多的數據,命中率更高,減少了磁盤IO,從而提升了數據庫性能。

一般來說,某業務實體中的各個數據項的訪問頻次是不一樣的,部分數據項可能是占用存儲空間比較大的BLOB或是TEXT。例如上例中的商品描述。所以,當表數據量很大時,可以將表按字段切開,將熱門字段、冷門字段分開放置在不同庫中,這些庫可以放在不同的存儲設備上,避免IO爭搶。垂直切分帶來的性能提升主要集中在熱門數據的操作效率上,而且磁盤爭用情況減少。

通常我們按以下原則進行垂直拆分:

  1. 把不常用的字段單獨放在一張表;
  2. 把text,blob等大字段拆分出來放在附表中;
  3. 經常組合查詢的列放在一張表中;

垂直分庫

通過垂直分表性能得到了一定程度的提升,但是還沒有達到要求,並且磁盤空間也快不夠了,因為數據還是始終限制在一台服務器,庫內垂直分表只解決了單一表數據量過大的問題,但沒有將表分布到不同的服務器上,因此每個表還是競爭同一個物理機的CPU、內存、網絡IO、磁盤。

經過思考,他把原有的SELLER_DB(賣家庫),分為了PRODUCT_DB(商品庫)和STORE_DB(店鋪庫),並把這兩個庫分散到不同服務器,如下圖:
在這里插入圖片描述
由於商品信息與商品描述業務耦合度較高,因此一起被存放在PRODUCT_DB(商品庫);而店鋪信息相對獨立,因此單獨被存放在STORE_DB(店鋪庫)。

垂直分庫是指按照業務將表進行分類,分布到不同的數據庫上面,每個庫可以放在不同的服務器上,它的核心理念是專庫專用。

它帶來的提升是:

  • 解決業務層面的耦合,業務清晰

  • 能對不同業務的數據進行分級管理、維護、監控、擴展等

  • 高並發場景下,垂直分庫一定程度的提升IO、數據庫連接數、降低單機硬件資源的瓶頸

    垂直分庫通過將表按業務分類,然后分布在不同數據庫,並且可以將這些數據庫部署在不同服務器上,從而達到多個服務器共同分攤壓力的效果,但是依然沒有解決單表數據量過大的問題。

水平分庫

經過垂直分庫后,數據庫性能問題得到一定程度的解決,但是隨着業務量的增長,PRODUCT_DB(商品庫)單庫存儲數據已經超出預估。粗略估計,目前有8w店鋪,每個店鋪平均150個不同規格的商品,再算上增長,那商品數量得往1500w+上預估,並且PRODUCT_DB(商品庫)屬於訪問非常頻繁的資源,單台服務器已經無法支撐。此時該如何優化?

再次分庫?但是從業務角度分析,目前情況已經無法再次垂直分庫。

嘗試水平分庫,將店鋪ID為單數的和店鋪ID為雙數的商品信息分別放在兩個庫中。

在這里插入圖片描述
也就是說,要操作某條數據,先分析這條數據所屬的店鋪ID。如果店鋪ID為雙數,將此操作映射至RRODUCT_DB1(商品庫1);如果店鋪ID為單數,將操作映射至RRODUCT_DB2(商品庫2)。此操作要訪問數據庫名稱的表達式為RRODUCT_DB[店鋪ID%2 + 1] 。

水平分庫是把同一個表的數據按一定規則拆到不同的數據庫中,每個庫可以放在不同的服務器上。

垂直分庫是把不同表拆到不同數據庫中,它是對數據行的拆分,不影響表結構

它帶來的提升是:

  • 解決了單庫大數據,高並發的性能瓶頸。
  • 提高了系統的穩定性及可用性。

穩定性體現在IO沖突減少,鎖定減少,可用性指某個庫出問題,部分可用`

當一個應用難以再細粒度的垂直切分,或切分后數據量行數巨大,存在單庫讀寫、存儲性能瓶頸,這時候就需要進行水平分庫了,經過水平切分的優化,往往能解決單庫存儲量及性能瓶頸。但由於同一個表被分配在不同的數據庫,需要額外進行數據操作的路由工作,因此大大提升了系統復雜度。

水平分表

按照水平分庫的思路對他把PRODUCT_DB_X(商品庫)內的表也可以進行水平拆分,其目的也是為解決單表數據量大的問題,如下圖:
在這里插入圖片描述
與水平分庫的思路類似,不過這次操作的目標是表,商品信息及商品描述被分成了兩套表。如果商品ID為雙數,將此操作映射至商品信息1表;如果商品ID為單數,將操作映射至商品信息2表。此操作要訪問表名稱的表達式為商品信息[商品ID%2 + 1] 。

水平分表是在同一個數據庫內,把同一個表的數據按一定規則拆到多個表中。

它帶來的提升是:

  • 優化單一表數據量過大而產生的性能問題

  • 避免IO爭搶並減少鎖表的幾率

    庫內的水平分表,解決了單一表數據量過大的問題,分出來的小表中只包含一部分數據,從而使得單個表的數據量變小,提高檢索性能。

總結

垂直分表:可以把一個寬表的字段按訪問頻次、是否是大字段的原則拆分為多個表,這樣既能使業務清晰,還能提升部分性能。拆分后,盡量從業務角度避免聯查,否則性能方面將得不償失。

垂直分庫:可以把多個表按業務耦合松緊歸類,分別存放在不同的庫,這些庫可以分布在不同服務器,從而使訪問壓力被多服務器負載,大大提升性能,同時能提高整體架構的業務清晰度,不同的業務庫可根據自身情況定制優化方案。但是它需要解決跨庫帶來的所有復雜問題。

水平分庫:可以把一個表的數據(按數據行)分到多個不同的庫,每個庫只有這個表的部分數據,這些庫可以分布在不同服務器,從而使訪問壓力被多服務器負載,大大提升性能。它不僅需要解決跨庫帶來的所有復雜問題,還要解決數據路由的問題(數據路由問題后邊介紹)。

水平分表:可以把一個表的數據(按數據行)分到多個同一個數據庫的多張表中,每個表只有這個表的部分數據,這樣做能小幅提升性能,它僅僅作為水平分庫的一個補充優化。

一般來說,在系統設計階段就應該根據業務耦合松緊來確定垂直分庫,垂直分表方案,在數據量及訪問壓力不是特別大的情況,首先考慮緩存、讀寫分離、索引技術等方案。若數據量極大,且持續增長,再考慮水平分庫水平分表方案。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM