Mysql分表和表分區詳解
為什么要分表和分區?
日常開發中我們經常會遇到大表的情況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過於龐大,導致數據庫在查詢和插入的時候耗時太長,性能低下,如果涉及聯合查詢的情況,性能會更加糟糕。分表和表分區的目的就是減少數據庫的負擔,提高數據庫的效率,通常點來講就是提高表的增刪改查效率。
什么是分表?
分表就是將一個大表按照一定的規則分解成多張具有獨立存儲空間的實體表,我們也可以成為子表,每個表都對應三個文件,MYD數據文件,MYI索引文件,frm表結構文件。這些子表可以分布在同一塊磁盤上,也可以在不同的機器上。App讀寫的時候根據事先定義好的規則得到對應的子表名,然后去操作它。
什么是分區?
分區和分表相似,都是按照規則分解表。不同在於分表將大表分解為若干個獨立的實體表,而分區是將數據分段在多個位置存放,可以是同一個磁盤也可以在不同的機器。分區后,表面上還是一張表,但數據分散到多個位置了。App讀寫的時候操作的還是大表名字,db自動去組織分區的數據。
Mysql分表和分區有什么聯系呢?
1、都是提高mysql的性能,在高並發狀態下都有一個良好的表現。
2、分表和分區不矛盾,對於大訪問量,並且表數據比較多的表,我們可以采取分表和分區的方式(如果merge這種分表方式,不能和分區配合實話,可以用其他的分表試),訪問量不大,但是表數據很多的表,我們可以采取分區的方式等。
3、分表技術是比較麻煩的,需要手動去創建子表,app服務端讀寫時候需要計算子表表名。采用merge好一些,但也要創建子表和配置子表間的union關系。
4、表分區相對於分表,操作方便,不需要創建子表。
分表的集中方式:
1、mysql集群
它並不是分表,但起到了和分表相同的作用。集群可分擔數據庫的操作次數,將任務分擔到多台數據庫上。集群可以讀寫分離,減輕讀寫壓力。從而提升數據庫性能。
2、自定義規則分表
大表可以按照業務的規則來分解為多個子表。通常為一下幾種類型,也可以自定義規則。
A:Range(范圍)--這種模式允許將數據划分不同的范圍。例如可以將一個表划分成若干個分區。
B:Hash(哈希)--這種模式允許通過對表的一個或多個列的Hash Key進行計算,最后通過這個Hash碼不同數值對應的數據區域進行划分。例如可以建立一個表主鍵進行分區的表。
C:Key(鍵值)--上面Hash模式的一種延伸,這里的Hash Key是mysql系統產生的。
D:List(預定義列表)--這種模式允許系統通過預定義的列表的值對數據進行分割。
E:Composite(復合模式)--以上模式的組合使用。
下面以Range簡單介紹下如何分表(按照年份表)。
假設表結構有4個字段:自增id、姓名、存款金額、存款日期
把存款日期作為規則分表。分表創建幾個表
2011年:account_2011
2012年:account_2012
.......
2015年:account_2015
App在讀寫的時候根據日期來查找對應的表名,需要手動來判斷。
var getTableName = function(){
var data = {
name:'tom',
money:=2800.00,
date:'201410013059'
};
var tablename = 'account_';
var year = parseInt(data.date.substring(0,4));
if(year < 2012){
tablename += 2011;
}else if(year < 2013){
tablename += 2012;
}else if(year < 2014){
tablename += 2013;
}else if(year < 2015){
tablename += 2014;
}else{
tablename += 2015;
}
return tablename;
}
3、利用merge存儲引擎來實現分表
Merge分表,分為主表和子表,主表類似於一個殼子,邏輯上封裝了子表,實際上數據都是存儲在子表中。
我們可以通過主表插入和查詢數據,如果清楚分表規律,也可以直接操作子表。
子表2011年:
CREATE TABLE `account_2011`(
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) CHARACTER SET utf8 COLLATE utf_general_ci NULL DEFAULT NULL,
`money` float NOT NULL,
`tradeDate` datetime NOT NULL
PRIMARY KEY (`id`)
)
ENGINE=MYISAM
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=2
CHECKSUM=0
ROW_FORMAT=DYNAMIC
DELAY_KEY_WRITE=0;
子表2012年:
CREATE TABLE `account_2012`(
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) CHARACTER SET utf8 COLLATE utf_general_ci NULL DEFAULT NULL,
`money` float NOT NULL,
`tradeDate` datetime NOT NULL
PRIMARY KEY (`id`)
)
ENGINE=MYISAM
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
AUTO_INCREMENT=2
CHECKSUM=0
ROW_FORMAT=DYNAMIC
DELAY_KEY_WRITE=0;
主表,所有年:
CREATE TABLE `account_all`(
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) CHARACTER SET utf8 COLLATE utf_general_ci NULL DEFAULT NULL,
`money` float NOT NULL,
`tradeDate` datetime NOT NULL
PRIMARY KEY (`id`)
)
ENGINE=MYISAM
DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci
UNION=(`account_2011`,`account_2012`)
INSERT_METHOD=LAST
ROW_FORMAT=DYNAMIC;
創建主表的時候有個INSERT_METHOD,致命插入方式,取值可以是:0不允許插入、FIRST插入到UNION中的第一個表、LAST插入到UNION中最后一個表。
通過主表查詢的時候,相當於將所有子表合在一起查詢,這種並不能體現分表的優勢,建議還是查詢子表。