一、查看MySQL是否支持分區
1、MySQL5.6以及之前版本
show variables like '%partition%';
2、MySQL5.7
show plugins;
二、分區表的分類與限制
1、分區表分類
RANGE分區:基於屬於一個給定連續區間的列值,把多行分配給分區。
LIST分區:類似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇。
HASH分區:基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算。這個函數可以包含MySQL 中有效的、產生非負整數值的任何表達式。
KEY分區:類似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL服務器提供其自身的哈希函數。必須有一列或多列包含整數值。
復合分區:在MySQL 5.6版本中,只支持RANGE和LIST的子分區,且子分區的類型只能為HASH和KEY。
2、分區表限制
1)分區鍵必須包含在表的所有主鍵、唯一鍵中。
2)MYSQL只能在使用分區函數的列本身進行比較時才能過濾分區,而不能根據表達式的值去過濾分區,即使這個表達式就是分區函數也不行。
3)最大分區數: 不使用NDB存儲引擎的給定表的最大可能分區數為8192(包括子分區)。如果當分區數很大,但是未達到8192時提示 Got error … from storage engine: Out of resources when opening file,可以通過增加open_files_limit系統變量的值來解決問題,當然同時打開文件的數量也可能由操作系統限制。
4)不支持查詢緩存: 分區表不支持查詢緩存,對於涉及分區表的查詢,它自動禁用。 查詢緩存無法啟用此類查詢。
5)分區的innodb表不支持外鍵。
6)服務器SQL_mode影響分區表的同步復制。 主機和從機上的不同SQL_mode可能會導致sql語句; 這可能導致分區之間的數據分配給定主從位置不同,甚至可能導致插入主機上成功的分區表在從庫上失敗。 為了獲得最佳效果,您應該始終在主機和從機上使用相同的服務器SQL模式。
7)ALTER TABLE … ORDER BY: 對分區表運行的ALTER TABLE … ORDER BY列語句只會導致每個分區中的行排序。
三、創建分區表
1、range分區
`id` int(11) NOT NULL,
`t` date NOT NULL,
PRIMARY KEY (`id`,`t`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
PARTITION BY RANGE (to_days(t))
(PARTITION p20170801 VALUES LESS THAN (736907) ENGINE = InnoDB,
PARTITION p20170901 VALUES LESS THAN (736938) ENGINE = InnoDB,
PARTITION pmax VALUES LESS THAN maxvalue ENGINE = InnoDB);123456789
+-----------+--------+
| 分區 | 行數 |
+-----------+--------+
| p20170801 | 1 |
| p20170901 | 3 |
+-----------+--------+
2 rows in set (0.00 sec)12345678
可以是用year、to_days、unix_timestamp等函數對相應的時間字段進行轉換,然后分區。
2、list分區
-> c1 INT,
-> c2 INT
-> )
-> PARTITION BY LIST(c1) (
-> PARTITION p0 VALUES IN (1, 4, 7),
-> PARTITION p1 VALUES IN (2, 5, 8)
-> );
Query OK, 0 rows affected (0.11 sec)123456789
ERROR 1525 (HY000): Table has no partition for value 312
3、hash分區
PARTITION BY HASH( YEAR(col3) )
PARTITIONS 4;123
= MOD(2005,4)
= 1123
4、key分區
id INT NOT NULL,
name VARCHAR(20),
UNIQUE KEY (id)
)
PARTITION BY KEY()
PARTITIONS 2;1234567
s1 CHAR(32) PRIMARY KEY
)
PARTITION BY KEY(s1)
PARTITIONS 10;12345
5、Column分區
1)針對日期字段的分區就不需要再使用函數進行轉換了,例如針對date字段進行分區不需要再使用YEAR()表達式進行轉換。
2)COLUMN分區支持多個字段作為分區鍵但是不支持表達式作為分區鍵。
1)所有的整型,float和decimal不支持
2)日期類型:date和datetime,其他不支持
3)字符類型:CHAR, VARCHAR, BINARY和VARBINARY,blob和text不支持
單列的column range分區mysql> show create table list_c;
CREATE TABLE `list_c` (
`c1` int(11) DEFAULT NULL,
`c2` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50500 PARTITION BY RANGE COLUMNS(c1)
(PARTITION p0 VALUES LESS THAN (5) ENGINE = InnoDB,
PARTITION p1 VALUES LESS THAN (10) ENGINE = InnoDB) */
多列的column range分區mysql> show create table list_c;
CREATE TABLE `list_c` (
`c1` int(11) DEFAULT NULL,
`c2` int(11) DEFAULT NULL,
`c3` char(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50500 PARTITION BY RANGE COLUMNS(c1,c3)
(PARTITION p0 VALUES LESS THAN (5,'aaa') ENGINE = InnoDB,
PARTITION p1 VALUES LESS THAN (10,'bbb') ENGINE = InnoDB) */
單列的column list分區mysql> show create table list_c;
CREATE TABLE `list_c` (
`c1` int(11) DEFAULT NULL,
`c2` int(11) DEFAULT NULL,
`c3` char(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50500 PARTITION BY LIST COLUMNS(c3)
(PARTITION p0 VALUES IN ('aaa') ENGINE = InnoDB,
PARTITION p1 VALUES IN ('bbb') ENGINE = InnoDB) */
6、子分區(組合分區)
PARTITION BY RANGE( YEAR(purchased) )
SUBPARTITION BY HASH( TO_DAYS(purchased) )
SUBPARTITIONS 2 (
PARTITION p0 VALUES LESS THAN (1990),
PARTITION p1 VALUES LESS THAN (2000),
PARTITION p2 VALUES LESS THAN MAXVALUE
);
[root@mycat-3 ~]# ll /data/mysql_data_3306/mysql_test/ts*
-rw-r----- 1 mysql mysql 8596 Aug 8 13:54 /data/mysql_data_3306/mysql_test/ts.frm
-rw-r----- 1 mysql mysql 98304 Aug 8 13:54 /data/mysql_data_3306/mysql_test/ts#P#p0#SP#p0sp0.ibd
-rw-r----- 1 mysql mysql 98304 Aug 8 13:54 /data/mysql_data_3306/mysql_test/ts#P#p0#SP#p0sp1.ibd
-rw-r----- 1 mysql mysql 98304 Aug 8 13:54 /data/mysql_data_3306/mysql_test/ts#P#p1#SP#p1sp0.ibd
-rw-r----- 1 mysql mysql 98304 Aug 8 13:54 /data/mysql_data_3306/mysql_test/ts#P#p1#SP#p1sp1.ibd
-rw-r----- 1 mysql mysql 98304 Aug 8 13:54 /data/mysql_data_3306/mysql_test/ts#P#p2#SP#p2sp0.ibd
-rw-r----- 1 mysql mysql 98304 Aug 8 13:54 /data/mysql_data_3306/mysql_test/ts#P#p2#SP#p2sp1.ibd
1234567891011121314151617
四、普通表轉換為分區表
1、用alter table table_name partition by命令重建分區表
alter table jxfp_data_bak PARTITION BY KEY(SH) PARTITIONS 8;
五、分區表操作
CREATE TABLE t1 (
id INT,
year_col INT
)
PARTITION BY RANGE (year_col) (
PARTITION p0 VALUES LESS THAN (1991),
PARTITION p1 VALUES LESS THAN (1995),
PARTITION p2 VALUES LESS THAN (1999)
);
1、ADD PARTITION (新增分區)
ALTER TABLE t1 ADD PARTITION (PARTITION p3 VALUES LESS THAN (2002));
2、DROP PARTITION (刪除分區)
ALTER TABLE t1 DROP PARTITION p0, p1;
3、TRUNCATE PARTITION(截取分區)
ALTER TABLE t1 TRUNCATE PARTITION p0;
ALTER TABLE t1 TRUNCATE PARTITION p1, p3;
4、COALESCE PARTITION(合並分區)
CREATE TABLE t2 (
name VARCHAR (30),
started DATE
)
PARTITION BY HASH( YEAR(started) )
PARTITIONS 6;
ALTER TABLE t2 COALESCE PARTITION 2;
5、REORGANIZE PARTITION(拆分/重組分區)
1)拆分分區
ALTER TABLE table ALGORITHM=INPLACE, REORGANIZE PARTITION;
ALTER TABLE employees ADD PARTITION (
PARTITION p5 VALUES LESS THAN (2010),
PARTITION p6 VALUES LESS THAN MAXVALUE
);
2)重組分區
ALTER TABLE members REORGANIZE PARTITION s0,s1 INTO (
PARTITION p0 VALUES LESS THAN (1970)
);
ALTER TABLE tbl_name
REORGANIZE PARTITION partition_list
INTO (partition_definitions);
ALTER TABLE members REORGANIZE PARTITION p0,p1,p2,p3 INTO (
PARTITION m0 VALUES LESS THAN (1980),
PARTITION m1 VALUES LESS THAN (2000)
);
ALTER TABLE tt ADD PARTITION (PARTITION np VALUES IN (4, 8));
ALTER TABLE tt REORGANIZE PARTITION p1,np INTO (
PARTITION p1 VALUES IN (6, 18),
PARTITION np VALUES in (4, 8, 12)
);
6、ANALYZE 、CHECK PARTITION(分析與檢查分區)
1)ANALYZE 讀取和存儲分區中值的分布情況
ALTER TABLE t1 ANALYZE PARTITION p1, ANALYZE PARTITION p2;
ALTER TABLE t1 ANALYZE PARTITION p1, p2;
2)CHECK 檢查分區是否存在錯誤
ALTER TABLE t1 ANALYZE PARTITION p1, CHECK PARTITION p2;
7、REPAIR分區
修復被破壞的分區
ALTER TABLE t1 REPAIR PARTITION p0,p1;
8、OPTIMIZE
該命令主要是用於回收空閑空間和分區的碎片整理。對分區執行該命令,相當於依次對分區執行 CHECK PARTITION, ANALYZE PARTITION,REPAIR PARTITION命令。
譬如:
ALTER TABLE t1 OPTIMIZE PARTITION p0, p1;
9、REBUILD分區
重建分區,它相當於先刪除分區中的數據,然后重新插入。這個主要是用於分區的碎片整理。
ALTER TABLE t1 REBUILD PARTITION p0, p1;
10、EXCHANGE PARTITION(分區交換)
分區交換的語法如下:
ALTER TABLE pt EXCHANGE PARTITION p WITH TABLE nt
其中,pt是分區表,p是pt的分區(注:也可以是子分區),nt是目標表。
其實,分區交換的限制還是蠻多的:
1) nt不能為分區表
2)nt不能為臨時表
3)nt和pt的結構必須一致
4)nt不存在任何外鍵約束,即既不能是主鍵,也不能是外鍵。
5)nt中的數據不能位於p分區的范圍之外。
具體可參考MySQL的官方文檔
11、遷移分區(DISCARD 、IMPORT )
ALTER TABLE t1 DISCARD PARTITION p2, p3 TABLESPACE;
ALTER TABLE t1 IMPORT PARTITION p2, p3 TABLESPACE;
源庫:192.168.2.200 mysql5.7.16 zhangdb下的emp_2分區表的
目標庫:192.168.2.100 mysql5.7.18 test下 (將zhangdb的emp表,導入到目標庫的test schema下)
MySQL [zhangdb]> CREATE TABLE emp_2(
id BIGINT unsigned NOT NULL AUTO_INCREMENT,
x VARCHAR(500) NOT NULL,
y VARCHAR(500) NOT NULL,
PRIMARY KEY(id)
)
PARTITION BY RANGE COLUMNS(id)
(
PARTITION p1 VALUES LESS THAN (1000),
PARTITION p2 VALUES LESS THAN (2000),
PARTITION p3 VALUES LESS THAN (3000)
);
(接着創建存儲過程,導入測試數據)
DELIMITER //
CREATE PROCEDURE insert_batch()
begin
DECLARE num INT;
SET num=1;
WHILE num < 3000 DO
IF (num%10000=0) THEN
COMMIT;
END IF;
INSERT INTO emp_2 VALUES(NULL, REPEAT('X', 500), REPEAT('Y', 500));
SET num=num+1;
END WHILE;
COMMIT;
END //
+------------+----------------+
| TABLE_NAME | PARTITION_NAME |
+------------+----------------+
| emp | NULL |
| emp_2 | p1 |
| emp_2 | p2 |
| emp_2 | p3 |
+------------+----------------+
4 rows in set (0.00 sec)
+----------+
| count(*) |
+----------+
| 999 |
+----------+
1 row in set (0.00 sec)
+----------+
| count(*) |
+----------+
| 1000 |
+----------+
1 row in set (0.00 sec)
+----------+
| count(*) |
+----------+
| 1000 |
+----------+
1 row in set (0.00 sec)
從上面可以看出,emp_2分區表已經創建完成,並且有3個子分區,每個分區都有一點數據。
MySQL [test]> CREATE TABLE `emp_2` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`x` varchar(500) NOT NULL,
`y` varchar(500) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3000 DEFAULT CHARSET=utf8mb4
/*!50500 PARTITION BY RANGE COLUMNS(id)
(PARTITION p1 VALUES LESS THAN (1000) ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN (3000) ENGINE = InnoDB) */ ;
-rw-r----- 1 mysql mysql 98304 May 25 15:58 emp_2#P#p0.ibd
-rw-r----- 1 mysql mysql 98304 May 25 15:58 emp_2#P#p1.ibd
-rw-r----- 1 mysql mysql 98304 May 25 15:58 emp_2#P#p2.ibd
※約束條件、字符集等等也必須一致,建議使用show create table t1; 來獲取創建表的SQL,否則在新服務器上導入表空間的時候會提示1808錯誤。
MySQL [test]> alter table emp_2 discard tablespace;
Query OK, 0 rows affected (0.12 sec)
-rw-r----- 1 mysql mysql 8604 May 25 04:14 emp_2.frm
mysql> flush tables emp_2 for export;
Query OK, 0 rows affected (0.00 sec)
[root@localhost test]# chown mysql.mysql emp_2#*
Query OK, 0 rows affected (0.96 sec)
+----------+
| count(*) |
+----------+
| 2999 |
+----------+
1 row in set (0.63 sec)
從上面的查看得知,分區表都已經導入到目標數據庫中了,
將部分子分區導入到目標數據庫的方法是:
1)在創建目標表的時候,只需要創建要導入的分區即可,如: 只創建了p2 p3兩個分區
CREATE TABLE `emp_2` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`x` varchar(500) NOT NULL,
`y` varchar(500) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3000 DEFAULT CHARSET=utf8mb4
/*!50500 PARTITION BY RANGE COLUMNS(id)
(
PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN (3000) ENGINE = InnoDB) */
3)其他的操作方法都一樣了。
六、如何獲取分區的相關信息
1. 通過 SHOW CREATE TABLE 語句來查看分區表的分區子句
譬如:mysql> show create table e/G
2. 通過 SHOW TABLE STATUS 語句來查看表是否分區對應Create_options字段
譬如:
mysql> show table status/G
*************************** 1. row ***************************
Name: e Engine: InnoDB Version: 10 Row_format: Compact Rows: 6 Avg_row_length: 10922 Data_length: 65536Max_data_length: 0 Index_length: 0 Data_free: 0 Auto_increment: NULL Create_time: 2015-12-07 22:26:06 Update_time: NULL Check_time: NULL Collation: latin1_swedish_ci Checksum: NULL Create_options: partitioned Comment:
3. 查看 INFORMATION_SCHEMA.PARTITIONS表
4. 通過 EXPLAIN PARTITIONS SELECT 語句查看對於具體的SELECT語句,會訪問哪個分區。
七、MySQL5.7對於partition表的改進
index condition pushdown:MySQL5.7.3分區表開始支持ICP;
load data:MySQL5.7開始使用緩存來實現性能提升,每個分區使用130KB緩沖區來實現這一點;
Per-partition索引緩存:MySQL5.7開始支持使用CACHE INDEX和LOAD INDEX INTO CACHE語句對分區的MyISAM表支持索引緩存;
FOR EXPORT選項(FLUSH TABLES):MySQL 5.7.4分區的InnoDB表開始支持FLUSH TABLES語句FOR EXPORT選項;
從MySQL 5.7.2開始,子分區支持ANALYZE,CHECK,OPTIMIZE,REPAIR和TRUNCATE操作;