平常開發中,咱們常常會遇到大表(指存儲了百萬級乃至千萬級條記錄的表)。
這樣的表過於龐大,致使數據庫在查詢和插入的時候耗時太長,性能低下,若是涉及聯合查詢的狀況,性能會更加糟糕。分表和表分區的目的 就是減小數據庫的負擔,提升數據庫的效率,一般點來說就是提升表的增刪改查效率。javascript
分表是將一個大表按照必定的規則分解成多張具備獨立存儲空間的實體表,咱們能夠稱爲子表。
每一個表都對應三個文件,MYD數據文件,.MYI索引文件,.frm表結構文件。這些子表能夠分佈在同一塊磁盤上,也能夠在不一樣的機器上。
App讀寫的時候根據事先定義好的規則獲得對應的子表名,而後去操做它。java
分區和分表類似,都是按照規則分解表。不一樣在於分表將大表分解爲若干個獨立的實體表,而分區是將數據分段劃分在多個位置存放,能夠是同一塊磁盤也能夠在不一樣的機器。分區後,表面上仍是一張表,但數據散列到多個位置了。App讀寫的時候操做的仍是大表名字,db自動去組織分區的數據。數據庫
都能提升MySQL的性能,在高併發狀態下都有一個良好的表現。併發
分表和分區不矛盾,能夠相互配合的,對於那些大訪問量,而且表數據比較多的表,咱們能夠採起分表和分區結合的方式(若是merge這種分表方式,不能和分區配合的話,能夠用其餘的分表試),訪問量不大,可是表數據不少的表,咱們能夠採起分區的方式等。less
分表技術是比較麻煩的,須要手動去建立子表,App服務端讀寫時候須要計算子表名。採用merge好一些,但也要建立子表和配置子表間的union關係。高併發
表分區相對於分表,操做方便,不須要建立子表。性能
它並非分表,但起到了和分表相同的做用。集羣可分擔數據庫的操做次數,將任務分擔到多臺數據庫上。集羣能夠讀寫分離,減小讀寫壓力。從而提高數據庫性能。code
大表能夠按照業務的規則來分解爲多個子表。一般爲如下幾種類型,也可本身定義規則。索引
Range(範圍)–這種模式容許將數據劃分不一樣範圍。例如能夠將一個表經過年份劃分紅若干個分區。 Hash(哈希)–這中模式容許經過對錶的一個或多個列的Hash Key進行計算,最後經過這個Hash碼不一樣數值對應的數據區域進行分區。例如能夠創建一個對錶主鍵進行分區的表。 Key(鍵值)-上面Hash模式的一種延伸,這裏的Hash Key是MySQL系統產生的。 List(預約義列表)–這種模式容許系統經過預約義的列表的值來對數據進行分割。 Composite(複合模式) –以上模式的組合使用
分表規則與分區規則同樣,在分區模塊詳細介紹。
下面以Range簡單介紹下如何分表(按照年份表)。ip
假設表結構有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; // account_2011 } else if (year < 2013) { tablename += 2012; // account_2012 } else if (year < 2014) { tablename += 2013; // account_2013 } else if (year < 2015) { tablename += 2014; // account_2014 } else { tablename += 2015; // account_2015 } return tablename; }
merge分表,分爲主表和子表,主表相似於一個殼子,邏輯上封裝了子表,實際上數據都是存儲在子表中的。
咱們能夠經過主表插入和查詢數據,若是清楚分表規律,也能夠直接操做子表。
子表 2011年:
CREATE TABLE `account_2011` ( `id` int(11) NOT NULL AUTO_INCREMENT , `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_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 utf8_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 utf8_general_ci NULL DEFAULT NULL , `money` float NOT NULL , `tradeDate` datetime NOT NULL PRIMARY KEY (`id`) ) ENGINE=MRG_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中的最後一個表。
經過主表查詢的時候,至關於將全部子表合在一塊兒查詢。這樣並不能體現分表的優點,建議仍是查詢子表。
Range:
create table range( id int(11), money int(11) unsigned not null, date datetime )partition by range(year(date))( partition p2007 values less than (2008), partition p2008 values less than (2009), partition p2009 values less than (2010) partition p2010 values less than maxvalue );
List:
create table list( 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) );
Hash:
create table hash( a int(11), b datetime )partition by hash (YEAR(b) partitions 4;
Key:
create table t_key( a int(11), b datetime) partition by key (b) partitions 4;
ALTER TABLE sale_data ADD PARTITION (PARTITION p201010 VALUES LESS THAN (201011));
當刪除了一個分區,也同時刪除了該分區中全部的數據。
ALTER TABLE sale_data DROP PARTITION p201010;
下面的SQL,將p201001 - p201009 合併爲3個分區p2010Q1 - p2010Q3
ALTER TABLE sale_data REORGANIZE PARTITION p201001,p201002,p201003, p201004,p201005,p201006, p201007,p201008,p201009 INTO ( PARTITION p2010Q1 VALUES LESS THAN (201004), PARTITION p2010Q2 VALUES LESS THAN (201007), PARTITION p2010Q3 VALUES LESS THAN (201010) );