1. 程式人生 > >建立mysql表分割槽的方法

建立mysql表分割槽的方法

表分割槽是最近才知道的哦 ,以前自己做都是分表來實現上億級別的資料了,下面我來給大家介紹一下mysql表分割槽建立與使用吧,希望對各位同學會有所幫助。
表分割槽的測試使用,主要內容來自於其他部落格文章以及mysql5.1的參考手冊
mysql測試版本:mysql5.5.28
mysql物理儲存檔案(有mysql配置的datadir決定儲存路徑)格式簡介
資料庫engine為MYISAM

frm表結構檔案,myd表資料檔案,myi表索引檔案。
INNODB engine對應的表物理儲存檔案
innodb的資料庫的物理檔案結構為:
.frm檔案
.ibd檔案和.ibdata檔案:
這兩種檔案都是存放innodb資料的檔案,之所以用兩種檔案來存放innodb的資料,是因為innodb的資料儲存方式能夠通過配置來決定是使用共享表空間存放儲存資料,還是用獨享表空間存放儲存資料。
獨享表空間儲存方式使用.ibd檔案,並且每個表一個ibd檔案
共享表空間儲存方式使用.ibdata檔案,所有表共同使用一個ibdata檔案
建立分割槽
分割槽的一些優點包括:
· 與單個磁碟或檔案系統分割槽相比,可以儲存更多的資料。
· 對於那些已經失去儲存意義的資料,通常可以通過刪除與那些資料有關的分割槽,很容易地刪除那些資料。相反地,在某些情況下,新增新資料的過程又可以通過為那些新資料專門增加一個新的分割槽,來很方便地實現。
通常和分割槽有關的其他優點包括下面列出的這些。MySQL 分割槽中的這些功能目前還沒有實現,但是在我們的優先順序列表中,具有高的優先順序;我們希望在5.1的生產版本中,能包括這些功能。
· 一些查詢可以得到極大的優化,這主要是藉助於滿足一個給定WHERE 語句的資料可以只儲存在一個或多個分割槽內,這樣在查詢時就不用查詢其他剩餘的分割槽。因為分割槽可以在建立了分割槽表後進行修改,所以在第一次配置分割槽方案時還不曾這麼做時,可以重新組織資料,來提高那些常用查詢的效率。
·  涉及到例如SUM() 和 COUNT()這樣聚合函式的查詢,可以很容易地進行並行處理。這種查詢的一個簡單例子如 “SELECT salesperson_id, COUNT(orders) as order_total FROM sales GROUP BY salesperson_id;”。通過“並行”, 這意味著該查詢可以在每個分割槽上同時進行,最終結果只需通過總計所有分割槽得到的結果。
·   通過跨多個磁碟來分散資料查詢,來獲得更大的查詢吞吐量。
簡而言之就是 資料管理優化,查詢更快,資料查詢並行
檢測mysql是否支援分割槽
複製程式碼
程式碼如下:
mysql> show variables like
"%partition%";
+-------------------+-------+
| Variable_name   | Value |
+-------------------+-------+
| have_partitioning | YES  |
+-------------------+-------+
1 row in set

RANGE 分割槽:基於屬於一個給定連續區間的列值,把多行分配給分割槽。
複製程式碼 程式碼如下:
DROP TABLE IF EXISTS `p_range`;
CREATE TABLE `p_range` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`name` char(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
/*!50100 PARTITION BY RANGE (id)
(PARTITION p0 VALUES LESS THAN (8) ENGINE = MyISAM) */;

range分割槽就是 partition by range(id) 表示按id 1-7的資料儲存在p0分割槽;如果id大於7了則資料不能寫入了,因為沒有對應的資料分割槽來儲存;
所以這時在建立分割槽時需要使用maxvalues關鍵字了
複製程式碼
程式碼如下:
PARTITION BY RANGE (id)
(
PARTITION p0 VALUES LESS THAN (8),
PARTITION p1 VALUES LESS THAN MAXVALUE)

這樣就表示,所有id大於7的資料記錄存在在p1分割槽裡。
RANGE分割槽在如下場合特別有用:
·  當需要刪除“舊的”資料時。如果你使用上面最近的那個例子給出的分割槽方案,你只需簡單地使用 “ALTER TABLE employees DROP PARTITION p0;”來刪除所有在1991年前就已經停止工作的僱員相對應的所有行。對於有大量行的表,這比執行一個如“DELETE FROM employees WHERE YEAR(separated) <= 1990;”這樣的一個DELETE查詢要有效得多。
·  想要使用一個包含有日期或時間值,或包含有從一些其他級數開始增長的值的列。
·  經常執行直接依賴於用於分割表的列的查詢。例如,當執行一個如“SELECT COUNT(*) FROM employees WHERE YEAR(separated) = 2000 GROUP BY store_id;”這樣的查詢時,MySQL可以很迅速地確定只有分割槽p2需要掃描,這是因為餘下的分割槽不可能包含有符合該WHERE子句的任何記錄。
LIST 分割槽:類似於按RANGE分割槽,區別在於LIST分割槽是基於列值匹配一個離散值集合中的某個值來進行選擇。
list分割槽可以理解為按一個鍵的id區間進行資料儲存,比如型別表 1,2,3,4的所有記錄儲存在p0裡面,5,6,7,8存在在p1分割槽裡面
這裡與range分割槽一樣,如果現在有條記錄typeid是9,那麼這條記錄是不能存入的;
需要注意的是:LIST分割槽沒有類似如“VALUES LESS THAN MAXVALUE”這樣的包含其他值在內的定義。將要匹配的任何值都必須在值列表中找到。
複製程式碼
程式碼如下:
DROP TABLE IF EXISTS `p_list`;
CREATE TABLE `p_list` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`typeid` mediumint(10) NOT NULL DEFAULT '0',
`typename` char(20) DEFAULT NULL,
PRIMARY KEY (`id`,`typeid`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
/*!50100 PARTITION BY LIST (typeid)
(PARTITION p0 VALUES IN (1,2,3,4) ENGINE = MyISAM,
PARTITION p1 VALUES IN (5,6,7,8) ENGINE = MyISAM) */;

HASH分割槽:基於使用者定義的表示式的返回值來進行選擇的分割槽,該表示式使用將要插入到表中的這些行的列值進行計算。這個函式可以包含MySQL 中有效的、產生非負整數值的任何表示式。
HASH分割槽主要用來確保資料在預先確定數目的分割槽中平均分佈。在RANGE和LIST分割槽中,必須明確指定一個給定的列值或列值集合應該儲存在哪個分割槽中;而在HASH分割槽中,MySQL 自動完成這些工作,你所要做的只是基於將要被雜湊的列值指定一個列值或表示式,以及指定被分割槽的表將要被分割成的分割槽數量。
要使用HASH分割槽來分割一個表,要在CREATE TABLE 語句上新增一個“PARTITION BY HASH (expr)”子句,其中“expr”是一個返回一個整數的表示式。它可以僅僅是欄位型別為MySQL 整型的一列的名字。此外,你很可能需要在後面再新增一個“PARTITIONS num”子句,其中num 是一個非負的整數,它表示表將要被分割成分割槽的數量。如果沒有包括一個PARTITIONS子句,那麼分割槽的數量將預設為1。
複製程式碼 程式碼如下:
DROP TABLE IF EXISTS `p_hash`;
CREATE TABLE `p_hash` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`storeid` mediumint(10) NOT NULL DEFAULT '0',
`storename` char(255) DEFAULT NULL,
PRIMARY KEY (`id`,`storeid`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8
/*!50100 PARTITION BY HASH (storeid)
PARTITIONS 4 */;

InnoDB引擎
簡單點說就是資料的存入可以按 partition by hash(expr); 這裡的expr可以是鍵名也可以是表示式比如YEAR(time),如果是表示式的情況下
“但是應當記住,每當插入或更新(或者可能刪除)一行,這個表示式都要計算一次;這意味著非常複雜的表示式可能會引起效能問題,尤其是在執行同時影響大量行的運算(例如批量插入)的時候。 ”
在執行刪除、寫入、更新時這個表示式都會計算一次。
資料的分佈採用基於使用者函式結果的模數來確定使用哪個編號的分割槽。換句話,對於一個表示式“expr”,將要儲存記錄的分割槽編號為N ,其中“N = MOD(expr, num)”。
比如上面的storeid 為10;那麼 N=MOD(10,4) ;N是等於2的,那麼這條記錄就儲存在p2的分割槽裡面。
如果插入一個表示式列值為'2005-09-15′的記錄到表中,那麼儲存該條記錄的分割槽確定如下:MOD(YEAR('2005-09-01′),4)  =  MOD(2005,4)  =  1 ;就儲存在p1分割槽裡面了。
“MySQL 5.1 還支援一個被稱為“linear hashing(線性雜湊功能)”的變數,它使用一個更加複雜的演算法來確定新行插入到已經分割槽了的表中的位置。
線性雜湊分割槽和常規雜湊分割槽在語法上的唯一區別在於,在“PARTITION BY” 子句中新增“LINEAR”關鍵字;線性雜湊功能使用的一個線性的2的冪(powers-of-two)運演算法則
按照線性雜湊分割槽的優點在於增加、刪除、合併和拆分分割槽將變得更加快捷,有利於處理含有極其大量(1000GB)資料的表。
它的缺點在於,與使用常規HASH分割槽得到的資料分佈相比,各個分割槽間資料的分佈不大可能均衡。”
KEY 分割槽:類似於按HASH分割槽,區別在於KEY分割槽只支援計算一列或多列,且MySQL 伺服器提供其自身的雜湊函式。必須有一列或多列包含整數值。
複製程式碼 程式碼如下:
DROP TABLE IF EXISTS `p_key`;
CREATE TABLE `p_key` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`keyname` char(20) DEFAULT NULL,
`keyval` varchar(1000) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8
/*!50100 PARTITION BY KEY (id)
PARTITIONS 4 */;

按照KEY進行分割槽類似於按照HASH分割槽,除了HASH分割槽使用的使用者定義的表示式,而KEY分割槽的 雜湊函式是由MySQL 伺服器提供。MySQL 簇(Cluster)使用函式MD5()來實現KEY分割槽;對於使用其他儲存引擎的表,伺服器使用其自己內部的 雜湊函式,這些函式是基於與PASSWORD()一樣的運演算法則。
“CREATE TABLE … PARTITION BY KEY”的語法規則類似於建立一個通過HASH分割槽的表的規則。它們唯一的區別在於使用的關鍵字是KEY而不是HASH,並且KEY分割槽只採用一個或多個列名的一個列表。
與hash的區別就是,hash使用使用者定義的表示式如YEAR(time) ;而key分割槽則是由mysql伺服器提供的。同樣KEY也是可以使用linear線性key的,與hash linear是相同的演算法。
子分割槽:是分割槽表中每個分割槽的再次分割。
複製程式碼 程式碼如下:
DROP TABLE IF EXISTS `p_subpartition`;
CREATE TABLE `p_subpartition` (
`id` int(10) DEFAULT NULL,
`title` char(255) NOT NULL,
`createtime` date NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
/*!50100
PARTITION BY RANGE (YEAR(createtime))
SUBPARTITION BY HASH (MONTH(createtime))
(PARTITION p0 VALUES LESS THAN (2012)
(SUBPARTITION s1 ENGINE = MyISAM,
SUBPARTITION s2 ENGINE = MyISAM),
PARTITION p1 VALUES LESS THAN (2013)
(SUBPARTITION s3 ENGINE = MyISAM,
SUBPARTITION s4 ENGINE = MyISAM),
PARTITION p2 VALUES LESS THAN MAXVALUE
(SUBPARTITION s5 ENGINE = MyISAM,
SUBPARTITION s6 ENGINE = MyISAM)) */;

可以看到p_subpartition有三個分割槽p0,p1,p2;而這三個分割槽每一個又進一步分為2個分割槽。那麼整個表都就分為6個小分割槽;

可以看到代表p_sobpartitionp0.myd的檔案消失了,取代的是p_subpartition#p#p0#sp#s1.myd
在MySQL 5.1中,對於已經通過RANGE或LIST分割槽了的表再進行子分割槽是可能的。
子分割槽是分割槽表中每個分割槽的再次分割,子分割槽既可以使用HASH希分割槽,也可以使用KEY分割槽。這 也被稱為複合分割槽(composite partitioning)。
1,如果一個分割槽中建立了子分割槽,其他分割槽也要有子分割槽
2,如果建立了了分割槽,每個分割槽中的子分割槽數必有相同
3,同一分割槽內的子分割槽,名字不相同,不同分割槽內的子分割槽名子可以相同(5.1.50不適用)
分割槽注意點
1、重新分割槽時,如果原分割槽裡面存在maxvalue則新的分割槽裡面也必須包含maxvalue否則就錯誤。
alter table p_range2x
reorganize partition p1,p2
into (partition p0 values less than (5), partition p1 values less than maxvalue);
[Err] 1520 – Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range
2、分割槽刪除時,資料也同樣會被刪除
alter table p_range drop partition p0;
3、如果range分割槽列表裡面沒有maxvalue則如有新資料大於現在分割槽range資料值那麼這個資料是無法寫入到資料庫表的。
4、修改表名不需要 刪除分割槽後在進行更改,修改表名後分區儲存myd myi對應也會自動更改。
如果希望從所有分割槽刪除所有的資料,但是又保留表的定義和表的分割槽模式,使用TRUNCATE TABLE命令。(請參見13.2.9節,“TRUNCATE語法”)。
如果希望改變表的分割槽而又不丟失資料,使用“ALTER TABLE … REORGANIZE PARTITION”語句。參見下面的內容,或者在13.1.2節,“ALTER TABLE語法” 中參考關於REORGANIZE PARTITION的資訊。
5、對錶進行分割槽時,不論採用哪種分割槽方式如果表中存在主鍵那麼主鍵必須在分割槽列中。表分割槽的侷限性。
6、list方式分割槽沒有類似於range那種 less than maxvalue的寫法,也就是說list分割槽表的所有資料都必須在分割槽欄位的值列表集合中。
7、在MySQL 5.1版中,同一個分割槽表的所有分割槽必須使用同一個儲存引擎;例如,不能對一個分割槽使用MyISAM,而對另一個使用InnoDB。
8、分割槽的名字是不區分大小寫的,myp1與MYp1是相同的。
分割槽的管理
range與list分割槽的改變動作不能適用於hash與key方式的分割槽。刪除與新增動作是都能使用的。
以下面的例子
複製程式碼 程式碼如下:
DROP TABLE IF EXISTS `p_list`;
CREATE TABLE `p_list` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`typeid` mediumint(10) NOT NULL DEFAULT '0',
`typename` char(20) DEFAULT NULL,
PRIMARY KEY (`id`,`typeid`)
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
/*!50100 PARTITION BY LIST (typeid)
(PARTITION p0 VALUES IN (1,2,3,4) ENGINE = MyISAM,
PARTITION p1 VALUES IN (5,6,7,8) ENGINE = MyISAM) */;


range與list分割槽的管理
刪除分割槽
ALTER TABLE tr DROP PARTITION p1;
需要注意的是刪除分割槽後,該分割槽的所有資料都沒有了。同時刪除後存在一個重大影響也就是typeid為5,6,7,8的記錄是不能寫入到該表了的!
清空資料
如果想要保留表結構與分割槽結構可以使用 TRUNCATE TABLE 清空表
更改分割槽保留資料
ALTER TABLE tbl_name REORGANIZE PARTITION partition_list INTO (partition_definitions);如果想保留資料進行分割槽的更改
ALTER TABLE p_list REORGANIZE PARTITION p0 INTO (
 PARTITION s0 VALUES IN(1,2),
 PARTITION s1 VALUES IN(3,4),
);這樣就能進行分割槽的合併了,那怎麼進行拆分呢
ALTER TABLE p_list REORGANIZE PARTITION s0,s1 INTO (
 PARTITION p0 VALUES IN(1,2,3,4),
); 使用 REORGANIZE PARTITION進行資料的合併與拆分,資料是沒有丟失的。
在使用REORGANIZE進行重新分割槽時,需要注意幾點:
1、用來確定新分割槽模式的PARTITION子句使用與用在CREATE TABLE中確定分割槽模式的PARTITION子句相同的規則。(partition 分割槽子句必須與建立原分割槽時的規則相同)
2、partition_definitions 列表中分割槽的合集應該與在partition_list 中命名分割槽的合集佔有相同的區間或值集合。 (不管是合併還是拆分,s0,s1到p0;p0到s0,s1 裡面的區間或者值都必須相同)
3、對於按照RANGE分割槽的表,只能重新組織相鄰的分割槽;不能跳過RANGE分割槽。(比如按range年份 p0 1990,p1 2000 ,p2 2013三個分割槽;在合併時partition p0,p2 into()
   這樣是不行的,因為這兩個分割槽不是相鄰的分割槽;)
4、不能使用REORGANIZE PARTITION來改變表的分割槽型別;也就是說,例如,不能把RANGE分割槽變為HASH分割槽,反之亦然。也不能使用該命令來改變分割槽表示式或列。
增加分割槽
ALTER TABLE p_list ADD PARTITION (PARTITION p2 VALUES IN (9, 10, 11));
但是不能使用
ALTER TABLE p_list ADD PARTITION (PARTITION p2 VALUES IN (9, 14));
這樣mysql 會產生錯誤1465 (HY000): 在LIST分割槽中,同一個常數的多次定義
hash與key分割槽的管理在改變分割槽設定方面,按照HASH分割槽或KEY分割槽的表彼此非常相似,但是它們又與按照RANGE或LIST分割槽的表在很多方面有差別。
關於新增和刪除按照RANGE或LIST進行分割槽的表的分割槽
不能使用與從按照RANGE或LIST分割槽的表中刪除分割槽相同的方式,來從HASH或KEY分割槽的表中刪除分割槽。但是,可以使用“ALTER TABLE ... COALESCE PARTITION”命令來合併HASH或KEY分割槽。
檢視原始碼列印幫助1 DROP TABLE IF EXISTS `p_hash`;  2    3 CREATE TABLE `p_hash` (  4 `id` int(10) NOT NULL AUTO_INCREMENT,  5 `storeid` mediumint(10) NOT NULL DEFAULT '0',  6 `storename` char(255) DEFAULT NULL,  7 PRIMARY KEY (`id`,`storeid`)  8 ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8  9 /*!50100 PARTITION BY HASH (storeid)  10 PARTITIONS 4 */;
如p_hash的分割槽數為4個;
要減少分割槽數為2個
ALTER TABLE p_hash COALESCE PARTITION 2;
對於按照HASH,KEY,LINEAR HASH,或LINEAR KEY分割槽的表, COALESCE能起到同樣的作用。COALESCE不能用來增加分割槽的數量,如果你嘗試這麼做,結果會出現類似於下面的錯誤:
mysql> ALTER TABLE clients COALESCE PARTITION 18;
錯誤1478 (HY000): 不能移動所有分割槽,使用DROP TABLE代替要增加顧客表的分割槽數量從12到18,使用“ALTER TABLE … ADD PARTITION”,具體如下:
ALTER TABLE clients ADD PARTITION PARTITIONS 18;註釋:“ALTER TABLE … REORGANIZE PARTITION”不能用於按照HASH或HASH分割槽的表。
分割槽維護
重建分割槽
這和先刪除儲存在分割槽中的所有記錄,然後重新插入它們,具有同樣的效果。它可用於整理分割槽碎片。
ALTER TABLE t1 REBUILD PARTITION (p0, p1);
優化分割槽如果從分割槽中刪除了大量的行,或者對一個帶有可變長度的行(也就是說,有VARCHAR,BLOB,或TEXT型別的列)作了許多修改,
可以使用“ALTER TABLE … OPTIMIZE PARTITION”來收回沒有使用的空間,並整理分割槽資料檔案的碎片。
ALTER TABLE t1 OPTIMIZE PARTITION (p0, p1);
分析分割槽
讀取並儲存分割槽的鍵分佈
ALTER TABLE t1 ANALYZE PARTITION (p3);
修補分割槽: 修補被破壞的分割槽。
ALTER TABLE t1 REPAIR PARTITION (p0,p1);
檢查分割槽
可以使用幾乎與對非分割槽表使用CHECK TABLE 相同的方式檢查分割槽。
ALTER TABLE trb3 CHECK PARTITION (p1);
這個命令可以告訴你表t1的分割槽p1中的資料或索引是否已經被破壞。如果發生了這種情況,使用“ALTER TABLE ... REPAIR PARTITION”來修補該分割槽。獲取分割槽資訊
在mysql伺服器資訊資料庫裡面的partitions存放著伺服器所有表的分割槽資訊。
複製程式碼 程式碼如下:
explain partitions命令
explain partitions select * from p_hash
+----+-------------+--------+-------------+------+---------------+------+---------+------+------+-------+
| id | select_type | table  | partitions  | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+--------+-------------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE    | p_hash | p0,p1,p2,p3 | ALL  | NULL      | NULL | NULL   | NULL |  10 |    |
+----+-------------+--------+-------------+------+---------------+------+---------+------+------+-------+

-- 獲取到p_list表的分割槽詳細資訊。
select * from information_schema.`PARTITIONS` where TABLE_NAME = 'p_list';
-- 分割槽的建立資訊
show create table p_list;