Mysql 分區表-分區操做

1、查看MySQL是否支持分區

一、MySQL5.6以及以前版本

show variables like '%partition%';html

二、MySQL5.7

show plugins;mysql

 

2、分區表的分類與限制

一、分區表分類

RANGE分區:基於屬於一個給定連續區間的列值,把多行分配給分區。react

LIST分區:相似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇。sql

HASH分區:基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算。這個函數能夠包含MySQL 中有效的、產生非負整數值的任何表達式。數據庫

KEY分區:相似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL服務器提供其自身的哈希函數。必須有一列或多列包含整數值。緩存

複合分區:在MySQL 5.6版本中,只支持RANGE和LIST的子分區,且子分區的類型只能爲HASH和KEY。服務器

二、分區表限制

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列語句只會致使每一個分區中的行排序。

8)全文索引。 分區表不支持全文索引,即便是使用InnoDB或MyISAM存儲引擎的分區表。
9)分區表沒法使用外鍵約束。
10)Spatial columns: 具備空間數據類型(如POINT或GEOMETRY)的列不能在分區表中使用。
11)臨時表: 臨時表不能分區。
12)subpartition問題: subpartition必須使用HASH或KEY分區。 只有RANGE和LIST分區可能被分區; HASH和KEY分區不能被子分區。
13)分區表不支持mysqlcheck,myisamchk和myisampack。
 

3、建立分區表

一、range分區

行數據基於一個給定的連續區間的列值放入分區。
CREATE TABLE `test_11` (
  `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
而後插入4條數據:
insert into test_11 values (1,"20170722"),(2,"20170822"),(3,"20170823"),(4,"20170824");1
而後查看information下partitions對分區別信息的統計:
select PARTITION_NAME as "分區",TABLE_ROWS as "行數" from information_schema.partitions where table_schema="mysql_test" and table_name="test_11";
+-----------+--------+
| 分區      | 行數   |
+-----------+--------+
| p20170801 |      1 |
| p20170901 |      3 |
+-----------+--------+
2 rows in set (0.00 sec)12345678
能夠看出分區p20170801插入1行數據,p20170901插入的3行數據。
能夠是用year、to_days、unix_timestamp等函數對相應的時間字段進行轉換,而後分區。

二、list分區

和range分區同樣,只是list分區面向的是離散的值
mysql> CREATE TABLE h2 (
    ->   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
與RANGE分區的狀況不一樣,沒有「catch-all」,如MAXVALUE; 分區表達式的全部預期值應在PARTITION … VALUES IN(…)子句中涵蓋。 包含不匹配的分區列值的INSERT語句失敗並顯示錯誤,如此示例所示:
mysql> INSERT INTO h2 VALUES (3, 5);
ERROR 1525 (HY000): Table has no partition for value 312

三、hash分區

根據用戶自定義表達式的返回值來進行分區,返回值不能爲負數
CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY HASH( YEAR(col3) )
    PARTITIONS 4;123
若是你插入col3的數值爲’2005-09-15’,那麼根據如下計算來選擇插入的分區:
MOD(YEAR('2005-09-01'),4)
    =  MOD(2005,4)
    =  1123

四、key分區

根據MySQL數據庫提供的散列函數進行分區
CREATE TABLE k1 (
    id INT NOT NULL,
    name VARCHAR(20),
    UNIQUE KEY (id)
)
PARTITION BY KEY()
PARTITIONS 2;1234567
KEY僅列出零個或多個列名稱。 用做分區鍵的任何列必須包含表的主鍵的一部分或所有,若是該表具備一個。 若是沒有列名稱做爲分區鍵,則使用表的主鍵(若是有)。若是沒有主鍵,可是有一個惟一的鍵,那麼惟一鍵用於分區鍵。可是,若是惟一鍵列未定義爲NOT NULL,則上一條語句將失敗。
與其餘分區類型不一樣,KEY使用的分區不限於整數或空值。 例如,如下CREATE TABLE語句是有效的:
CREATE TABLE tm1 (
    s1 CHAR(32) PRIMARY KEY
)
PARTITION BY KEY(s1)
PARTITIONS 10;12345
注意:對於key分區表,不能執行ALTER TABLE DROP PRIMARY KEY,由於這樣作會生成錯誤 ERROR 1466 (HY000): Field in list of fields for partition function not found in table. 

五、Column分區

COLUMN分區是5.5開始引入的分區功能,只有RANGE COLUMN和LIST COLUMN這兩種分區;支持整形、日期、字符串;RANGE和LIST的分區方式很是的類似。
COLUMNS和RANGE和LIST分區的區別
1)針對日期字段的分區就不須要再使用函數進行轉換了,例如針對date字段進行分區不須要再使用YEAR()表達式進行轉換。
2)COLUMN分區支持多個字段做爲分區鍵可是不支持表達式做爲分區鍵。
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) */ 

六、子分區(組合分區)

在分區的基礎上再進一步分區,有時成爲複合分區;
MySQL數據庫容許在range和list的分區上進行HASH和KEY的子分區。例如:
CREATE TABLE ts (id INT, purchased DATE)
    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
ts表根據purchased進行range分區,而後又進行了一次hash分區,最後造成了3*2個分區,能夠從物理文件證明此分區方式。能夠經過subpartition語法來顯示指定子分區名稱。
注意:每一個子分區的數量必須相同;若是一個分區表的任何子分區已經使用subpartition,那麼必須代表全部的子分區名稱;每一個subpartition子句必須包括子分區的一個名字;子分區的名字必須是一致的
另外,對於MyISAM表可使用index directory和data direactory來指定各個分區的數據和索引目錄,可是對於innodb表來講,由於該存儲引擎使用表空間自動的進行數據和索引的管理,所以會忽略指定index和data的語法。
 
 

4、普通錶轉換爲分區表

一、用alter table table_name partition by命令重建分區表

alter table jxfp_data_bak PARTITION BY KEY(SH) PARTITIONS 8;

 

5、分區表操做

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)
);

一、ADD PARTITION (新增分區)

ALTER TABLE t1 ADD PARTITION (PARTITION p3 VALUES LESS THAN (2002));

二、DROP PARTITION (刪除分區)

ALTER TABLE t1 DROP PARTITION p0, p1;

三、TRUNCATE PARTITION(截取分區)

ALTER TABLE t1 TRUNCATE PARTITION p0;

ALTER TABLE t1 TRUNCATE PARTITION p1, p3;

四、COALESCE PARTITION(合併分區)

CREATE TABLE t2 (
    name VARCHAR (30),
    started DATE
)
PARTITION BY HASH( YEAR(started) )
PARTITIONS 6;

ALTER TABLE t2 COALESCE PARTITION 2;

五、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)
);

六、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;

七、REPAIR分區

修復被破壞的分區

ALTER TABLE t1 REPAIR PARTITION p0,p1;

八、OPTIMIZE

該命令主要是用於回收空閒空間和分區的碎片整理。對分區執行該命令,至關於依次對分區執行 CHECK PARTITION, ANALYZE PARTITION,REPAIR PARTITION命令。

譬如:

ALTER TABLE t1 OPTIMIZE PARTITION p0, p1;

九、REBUILD分區

重建分區,它至關於先刪除分區中的數據,而後從新插入。這個主要是用於分區的碎片整理。

ALTER TABLE t1 REBUILD PARTITION p0, p1;

十、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的官方文檔

十一、遷移分區(DISCARD 、IMPORT )

ALTER TABLE t1 DISCARD PARTITION p2, p3 TABLESPACE;

ALTER TABLE t1 IMPORT PARTITION p2, p3 TABLESPACE;

實驗環境:(都是mysql5.7)
源庫:192.168.2.200      mysql5.7.16    zhangdb下的emp_2分區表的
目標庫:192.168.2.100    mysql5.7.18    test下  (將zhangdb的emp表,導入到目標庫的test schema下)
--:在源數據庫中建立測試分區表emp_2,而後導入數據
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 //
DELIMITER ;
mysql> select TABLE_NAME,PARTITION_NAME from information_schema.partitions where table_schema='zhangdb';
+------------+----------------+
| TABLE_NAME | PARTITION_NAME |
+------------+----------------+
| emp        | NULL           |
| emp_2      | p1             |
| emp_2      | p2             |
| emp_2      | p3             |
+------------+----------------+
4 rows in set (0.00 sec)
mysql> select count(*) from emp_2 partition (p1);
+----------+
| count(*) |
+----------+
|      999 |
+----------+
1 row in set (0.00 sec)
mysql> select count(*) from emp_2 partition (p2);
+----------+
| count(*) |
+----------+
|     1000 |
+----------+
1 row in set (0.00 sec)
mysql> select count(*) from emp_2 partition (p3);
+----------+
| count(*) |
+----------+
|     1000 |
+----------+
1 row in set (0.00 sec)
從上面能夠看出,emp_2分區表已經建立完成,而且有3個子分區,每一個分區都有一點數據。
--:在目標數據庫中,建立emp_2表的結構,不要數據(要在源庫,使用show create table emp_2\G 的方法 查看建立該表的sql)
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) */ ;
[root@localhost test]# ll
-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)
[root@localhost test]# ll    ---這時候在看,剛纔的3個分區的idb文件都沒有了
-rw-r----- 1 mysql mysql  8604 May 25 04:14 emp_2.frm
--:在源數據庫上運行FLUSH TABLES … FOR EXPORT 鎖定表並生成.cfg元數據文件,最後將cfg和ibd文件傳輸到目標數據庫中
mysql> flush tables emp_2 for export;
Query OK, 0 rows affected (0.00 sec)
[root@localhost zhangdb]# scp emp_2* root@192.168.2.100:/mysql/data/test/   --將文件cp到目標數據庫
mysql> unlock tables;   ---最後將表的鎖是否
--:在目標數據庫中對文件受權,而後導入表空間查看數據是否完整可用
[root@localhost test]# chown mysql.mysql emp_2#*
MySQL [test]> alter table emp_2 import tablespace;
Query OK, 0 rows affected (0.96 sec)
MySQL [test]> select count(*) from emp_2;
+----------+
| 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) */
2)從源庫cp到目標庫的文件,固然也就是這倆的,就不須要其餘分區的了,
3)其餘的操做方法都同樣了。

 

6、如何獲取分區的相關信息

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語句,會訪問哪一個分區。

 
 

7、MySQL5.7對於partition表的改進

HANDLER statements:MySQL 5.7.1分區表開始支持HANDLER語句;
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操做;
 
整理自:
https://dev.mysql.com/doc/refman/5.7/en/alter-table-partition-operations.html
https://www.2cto.com/database/201708/666142.html
http://blog.51cto.com/fengfeng688/2149492
https://www.aliyun.com/jiaocheng/1137826.html
相關文章
相關標籤/搜索