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

MySQL分割槽和分表

一、概念

1.為什麼要分表和分割槽?
日常開發中我們經常會遇到大表的情況,所謂的大表是指儲存了百萬級乃至千萬級條記錄的表。這樣的表過於龐大,導致資料庫在查詢和插入的時候耗時太長,效能低下,如果涉及聯合查詢的情況,效能會更加糟糕。分表和表分割槽的目的就是減少資料庫的負擔,提高資料庫的效率,通常點來講就是提高表的增刪改查效率。
2.什麼是分表?
分表是將一個大表按照一定的規則分解成多張具有獨立儲存空間的實體表,我們可以稱為子表,每個表都對應三個檔案,MYD資料檔案,.MYI索引檔案,.frm表結構檔案。這些子表可以分佈在同一塊磁碟上,也可以在不同的機器上。app讀寫的時候根據事先定義好的規則得到對應的子表名,然後去操作它。
3.什麼是分割槽?
分割槽和分表相似,都是按照規則分解表。不同在於分表將大表分解為若干個獨立的實體表,而分割槽是將資料分段劃分在多個位置存放,可以是同一塊磁碟也可以在不同的機器。分割槽後,表面上還是一張表,但資料雜湊到多個位置了。app讀寫的時候操作的還是大表名字,db自動去組織分割槽的資料。
4.mysql分表和分割槽有什麼聯絡呢?
(1)都能提高mysql的性高,在高併發狀態下都有一個良好的表現。
(2)分表和分割槽不矛盾,可以相互配合的,對於那些大訪問量,並且表資料比較多的表,我們可以採取分表和分割槽結合的方式(如果merge這種分表方式,不能和分割槽配合的話,可以用其他的分表試),訪問量不大,但是表資料很多的表,我們可以採取分割槽的方式等。
(3)分表技術是比較麻煩的,需要手動去建立子表,app服務端讀寫時候需要計運算元表名。採用merge好一些,但也要建立子表和配置子表間的union關係。
(4)表分割槽相對於分表,操作方便,不需要建立子表。

二、分割槽

1.分割槽的型別:
(1)Range:把連續區間按範圍劃分
例:

create table user(
    id int(11),
    money int(11) unsigned not null,
    date datetime
)
partition by range(YEAR(date))(
    partition p2014 values less than (2015),
    partition p2015 values less than (2016),
    partition p2016 values less than (2017),
    partition p2017 values less than maxvalue
);

(2)List:把離散值分成集合,按集合劃分,適合有固定取值列的表
例:

create table user(
    a int(11),
    b int(11)
)
partition by list(b)(
    partition p0 values in (1,3,5,7,9),
    partition p1 values in (2,4,6,8,0)
);

(3)Hash:隨機分配,分割槽數固定
例:

create table user(
    a int(11),
    b datetime
)
partition by hash(YEAR(b))
partitions 4;

(4)Key:類似Hash,區別是隻支援1列或多列,且mysql提供自身的Hash函式
例:

create table user(
    a int(11),
    b datetime
)
partition by key(b)
partitions 4;

2.分割槽管理
(1)新增分割槽

ALTER TABLE sale_data
ADD PARTITION (PARTITION p201710 VALUES LESS THAN (201711));

(2)刪除分割槽

--當刪除了一個分割槽,也同時刪除了該分割槽中所有的資料。
ALTER TABLE sale_data DROP PARTITION p201710;

(3)分割槽的合併
下面的SQL,將p201701 - p201709 合併為3個分割槽p2017Q1 - p2017Q3

ALTER TABLE sale_data
REORGANIZE PARTITION p201701,p201702,p201703,
p201704,p201705,p201706,
p201707,p201708,p201709 INTO
(
    PARTITION p2017Q1 VALUES LESS THAN (201704),
    PARTITION p2017Q2 VALUES LESS THAN (201707),
    PARTITION p2017Q3 VALUES LESS THAN (201710)
);

3.分割槽應該注意的事項:
(1)做分割槽時,要麼不定義主鍵,要麼把分割槽欄位加入到主鍵中。
(2)分割槽欄位不能為NULL,要不然怎麼確定分割槽範圍呢,所以儘量NOT NULL

三、分表

1.垂直分表
把原來有很多列的表拆分成多個表,原則是:
(1)把常用、不常用的欄位分開放
(2)把大欄位獨立存放在一個表中
2.水平分表
為了解決單表資料量過大的問題,每個水平拆分表的結構完全一致。
例:
(1)按時間結構
如果業務系統對時效性較高,比如新聞釋出系統的文章表,可以把資料庫設計成時間結構,按時間分有幾種結構:
(a)平板式
表類似:

article_201701
article_201702
article_201703

用年來分還是用月可自定,但用日期的話表就太多了,也沒這必要。一般建議是按月分就可以。
這種分法,其難處在於,假設我要列20條資料,結果這三張表裡都有2條,那麼業務上很有可能要求讀三次表。如果時間長了,有幾十張表,而每張表是0條,那不就是要讀完整個系統的表才行麼?另外這個結構,要作分頁是比較難實現的。
主鍵:在這個系統中,主鍵是13位帶毫秒的時間戳,不要用自動編號,否則難以通過主鍵定位到表,也可以在查詢時帶上時間,但比較煩瑣。
(b)歸檔式
表類似:

article_old
article_new

為了解決平板式的缺點,可以採用時間歸檔式設計,可以看到這個系統只有兩張表。一張是舊文章表,一張是新文章表,新文章表放2個月的資訊,每天定期把2
個月中的最早一天的文章歸入舊錶中。這樣一方面可以解決效能問題,因為一般新聞釋出系統讀取的都是新的內容,舊的內容讀取少;第二可以委婉地解決功能問
題,比如平板式所說的問題,在歸檔式中最多也只需要讀2張表就完成了。
歸檔式的缺點在於舊錶容量還是相對比較大,如果業務允許,可對舊錶中的超舊內容進行再歸檔或直接清理掉。
(2)按版塊結構
如果按照文章的所屬版塊進行拆表,比如新聞、體育版塊拆表,一方面可以使每個表資料量分離,另一方面是各版塊之間相互影響可降到最低。假如新聞版塊的資料表損壞或需要維護,並不會影響到體育版塊的正常工作,從而降低了風險。版塊結構同時常用於bbs這樣的系統。
板塊結構也有幾種分法:
(a)對應式
對於版塊數量不多,而且較為固定的形式,就直接對應就好。比如新聞版塊,可以分出新聞的目錄表,新聞的文章表等。

news_category
news_article
sports_category
sports_article

可看到每一個版塊都對應著一組相同的表結構,好處就是一目瞭然。在功能上,因為版塊之間還是有一些隔閡,所以需要聯合查詢的需求不多,開發上比時間結構的方式要輕鬆。
主鍵:依舊要考慮的,在這個系統中,主鍵是版塊+時間戳,單純的時間戳或自動編號也能用,查詢時要記得帶上版塊用於定位表。
(b)冷熱式
對應式的缺點是,如果版塊數量很大而且不確定,那要分出的表數量就太多了。舉個例子:百度貼吧,如果按一個詞條一個表設計,那得有多少張表呢?
用這樣的方式吧。

tieba_汽車
tieba_飛機
tieba_火箭
tieba_unite

這個表汽車、火箭表是屬於熱門表,定義為新建的版塊放在unite表裡面,待到其超過一萬張主貼的時候才開對應表結構。因為在貼吧這種系統中,冷門版塊
肯定比熱門版塊多得多,這些冷門版塊通常只有幾張帖子,為它們開表也太浪費了;同時熱門版塊數量和訪問量等,又比冷門版塊多得多,非常有特點。
unite表還可以擴充套件成雜湊表,利用詞條的md5編碼,可以分成n張表,我算了一下,md5前一位可分36張表,兩位即是1296張表,足夠了。

tieba_unite_ab
tieba_unite_ac

(3)按雜湊結構
雜湊結構通常用於部落格之類的基於使用者的場合,在部落格這樣的系統裡有幾個特點,1是使用者數量非常多,2是每個使用者發的文章數量都較少,3是使用者發文章不定
期,4是每個使用者發得不多,但總量仍非常之大。基於這些特點,用以上所說的任何一種分表方式都不合適,一沒有固定的時效不宜用時間拆,二使用者很多,而且還
偏偏都是冷門,所以也不宜用版塊(使用者)拆。
雜湊結構在上面有所提及,既然按每個使用者不好直接拆,那就把一群使用者歸進一個表好了。

blog_aa
blog_ab
blog_ac

如上所說,md5取前兩位雜湊可以達到1296張表,如果覺得不夠,那就再加一位,總數可達46656張表,還不夠?
表的數量太多,要建立這些表也是挺麻煩的,可以考慮在程式裡往資料庫insert之前,多執行一句判斷表存在與否並建立表的語句,很實用,消耗也並不很大。
主鍵:依舊要考慮的,在這個系統中,主鍵是使用者ID+時間戳,單純的時間戳或自動編號也能用,但查詢時要記得帶上使用者名稱用於定位表。
檢視更多:
MySQL優化
MySQL各儲存引擎
MySQL鎖詳解
MySQL事務
MySQL索引型別


參考資料:
http://blog.csdn.net/shmnh/article/details/44055059
http://blog.csdn.net/hijiankang/article/details/9173825
http://blog.csdn.net/feihong247/article/details/8100960
http://niehan.blog.techweb.com.cn/archives/279.html