1. 程式人生 > 實用技巧 >分割槽分表分庫

分割槽分表分庫


image.png

分割槽(加快訪問速度)

什麼時候分割槽?

一張表的查詢速度已經慢到影響使用的時候。

  • sql經過優化
  • 資料量大(表的大小超過2GB,一般單表撐死1000萬條)
  • 表中的資料是分段的(表中包含歷史資料,新的資料被增加都新的分割槽中)
  • 對資料的操作往往只涉及一部分資料,而不是所有的資料

從應用程式的角度來看,分割槽後的表與非分割槽表完全相同,使用 SQL DML 命令訪問分割槽後的表時,無需任何修改。

CREATE TABLE sales (

id INT AUTO_INCREMENT,

amount DOUBLE NOT NULL,

order_day DATETIME NOT NULL,

PRIMARY KEY(id, order_day)

) ENGINE=Innodb

PARTITION BY RANGE(YEAR(order_day)) (

PARTITION p_2010 VALUES LESS THAN (2010),

PARTITION p_2011 VALUES LESS THAN (2011),

PARTITION p_2012 VALUES LESS THAN (2012),

PARTITION p_catchall VALUES LESS THAN MAXVALUE);

Mysql的主從模式(分庫分表前的解決方案)

面對越來越多的請求,我們將資料庫的寫操作和讀操作進行分離, 使用多個從庫副本(Slaver Replication)負責讀,使用主庫(Master)負責寫, 從庫從主庫同步更新資料,保持資料一致。架構上就是資料庫主從同步。 從庫可以水平擴充套件,所以更多的讀請求不成問題。

但是當用戶量級上來後,寫請求越來越多,該怎麼辦?加一個Master是不能解決問題的, 因為資料要儲存一致性,寫操作需要2個master之間同步,相當於是重複了,而且更加複雜。(需要分散式一致性演算法維護)

這時就需要用到分庫分表(sharding),對寫操作進行切分。

資料庫的“寫”(寫10000條資料到oracle可能要3分鐘)操作是比較耗時的。但是資料庫的“讀”(從oracle讀10000條資料可能只要5秒鐘)


垂直切分和水平切分(分庫分表)

垂直分表(同一表的冷熱資料拆分)

也就是“大表拆小表”,基於列欄位進行的。一般是表中的欄位較多,將不常用的, 資料較大,長度較長(比如text型別欄位)的拆分到“擴充套件表“。 一般是針對那種幾百列的大表,也避免查詢時,資料量太大造成的“跨頁”問題。

​ 將訪問頻次低的商品描述資訊單獨存放在一張表中,訪問頻次較高的商品基本資訊單獨放在一張表中。

MySQL底層是通過資料頁儲存的,一條記錄佔用空間過大會導致跨頁,造成額外的效能開銷。

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

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

垂直分庫

通過垂直分表效能得到了一定程度的提升,但是還沒有達到要求,並且磁碟空間也快不夠了,因為資料還是始終限制在一臺伺服器,庫內垂直分表只解決了單一表資料量過大的問題,但沒有將表分佈到不同的伺服器上,因此每個表還是競爭同一個物理機的CPU、記憶體、網路IO、磁碟。

垂直分庫針對的是一個系統中的不同業務進行拆分,比如使用者User一個庫,商品Producet一個庫,訂單Order一個庫。 切分後,要放在多個伺服器上,而不是一個伺服器上。

水平分表分庫

  • RANGE

從0到10000一個表,10001到20000一個表;

  • HASH取模

一個商場系統,一般都是將使用者,訂單作為主表,然後將和它們相關的作為附表,這樣不會造成跨庫事務之類的問題。 取使用者id,然後hash取模,分配到不同的資料庫上。

比如美團的分庫分表的方案是32個數據庫例項,通過userId進行取模的話就是,將UserId後面4位模32然後丟到32個數據庫中,同時又將UserId後面4位除以32再mod32丟到32張表裡面,這樣就有1024張表,然後線上部署8個主從例項,每個例項4個數據庫。

如果頻繁用到的查詢條件中不帶sharding key時,將會導致無法定位資料庫,從而需要同時向多個庫發起查詢,再在記憶體中合併資料,取最小集返回給應用,分庫反而成為拖累。

  • 地理區域

比如按照華東,華南,華北這樣來區分業務,七牛雲應該就是如此。

  • 時間

按照時間切分,就是將6個月前,甚至一年前的資料切出去放到另外的一張表,因為隨著時間流逝,這些表的資料 被查詢的概率變小,所以沒必要和“熱資料”放在一起,這個也是“冷熱資料分離”。


分庫分表後面臨的問題

  • 事務支援

分庫分表後,就成了分散式事務了。如果依賴資料庫本身的分散式事務管理功能去執行事務,將付出高昂的效能代價; 如果由應用程式去協助控制,形成程式邏輯上的事務,又會造成程式設計方面的負擔。

  • 多庫結果集合並(group by,order by)

  • 跨庫join(水平分庫能join,垂直分庫不行)

分庫分表後表之間的關聯操作將受到限制,我們無法join位於不同分庫的表,也無法join分表粒度不同的表, 結果原本一次查詢能夠完成的業務,可能需要多次查詢才能完成。

粗略的解決方法:
(1)全域性表:基礎資料,所有庫都拷貝一份。
(2) 欄位冗餘:這樣有些欄位就不用join去查詢了。
(3)系統層組裝:分別查詢出所有,然後組裝起來,較複雜。

image.png

分散式下怎麼保障ID唯一

  1. 利用資料庫叢集並設定相應的步長(Flickr方案)
    優點:高可用、ID較簡潔。 缺點:需要單獨的資料庫叢集。

  2. Twitter Snowflake
    優點:高效能高可用、易拓展。 缺點:需要獨立的叢集以及ZK。

  3. 帶有業務屬性的方案: > 時間戳+使用者標識碼+隨機數

有下面幾個好處:

(1)方便、成本低。
基本無重複的可能。
(2)自帶分庫規則,這裡的使用者標識碼即為使用者ID的後四位,在查詢的場景下,只需要訂單號就可以匹配到相應的庫表而無需使用者ID,只取四位是希望訂單號儘可能的短一些,並且評估下來四位已經足夠。
(3)可排序,因為時間戳在最前面。