1.分區一般用於非常大的表,采用“分而治之”的策略,將一個很大的對象分成多個小對象進行管理,每個分區都是一個獨立的對象。
分區使用分區鍵將數據根據范圍值,特定列值或HASH值等規則分布在不同的分區中。查看當前MySQL是否支持分區,如下所示。
mysql> show variables like '%partition%'; --或者使用select @@have_partitioning; +-------------------+-------+ | Variable_name | Value | +-------------------+-------+ | have_partitioning | YES | +-------------------+-------+ 1 row in set (0.00 sec)
2.分區類型,主要分為以下四種:
RANGE:基於一個連續的區間范圍,將數據分配到不同的分區。
LIST:基於枚舉出的值列表分區
HASH:基於給定的分區數,將數據分配到不同的分區
KEY:類似於HASH分區,但不允許用戶自定義表達式
3.設置表的分區,類似指定表的存儲引擎,分區不支持CSV和merge引擎對象,如下所示
create table student( sno int not null, sname varchar(30) not null, sclass varchar(10) not null, sage int not null, sgender varchar(6) )engine=InnoDB default charset=utf8 partition by list columns(sgender)( partition p0 values in ('男'), partition p1 values in ('女') );
不管哪種分區類型,分區鍵必須是主鍵或唯一鍵,除非兩者都沒有,否者將會報如下錯誤。
Error Code: 1503. A PRIMARY KEY must include all columns in the table's partitioning function
4.RANGE分區
RANGE分區利用取值范圍來進行分區,區間必須連續且不重疊,使用values less than進行分區定義,分區鍵必須是INT,或者表達式返回INT。
create table users_par( id int not null, usrName varchar(50) not null, usrEmail varchar(50) not null, age int not null, regDate date not null )engine=InnoDB default charset=utf8 partition by range(age)( partition p0 values less than(20), partition p1 values less than(30), partition p2 values less than maxvalue --防止插入大於30歲的用戶,出現錯誤 );
如果是將注冊日期作為分區鍵,則須要使用日期處理函數轉換為整型,例如year(regDate),to_days(regDate),to_seconds(regDate),且只支持這三個函數。
或者使用RANGE COLUMNS分區,則不需要轉換日期,如下所示
create table users_par( id int not null, usrName varchar(50) not null, usrEmail varchar(50) not null, age int not null, regDate date not null )engine=InnoDB default charset=utf8 partition by range columns(regDate)( partition p0 values less than('2005-05-05'), partition p1 values less than('2009-09-09'), partition p2 values less than('2015-05-05'), );
RANGE分區特別適用於刪除過期數據或者某范圍數據,只需要alter table tbl_name truncate partition partition_name即可,比delete語句效率要高很多,還有就是經常使用分區鍵的查詢,可以提高查詢性能,因為只需掃描某些分區就OK,如下所示。
mysql> explain partitions select * from users_par where age=30; +----+-------------+-----------+------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | users_par | p2 | ALL | NULL | NULL | NULL | NULL | 2 | Using where | +----+-------------+-----------+------------+------+---------------+------+---------+------+------+-------------+
5.LIST分區
LIST分區是建立離散的值列表來實現特定的值屬於哪個分區,使用partition by list來實現,values in 來定義。
CREATE TABLE `student` ( `sno` int(11) NOT NULL, `sname` varchar(30) NOT NULL, `sclass` varchar(10) NOT NULL, `sage` int(11) NOT NULL, `sgender` varchar(6) DEFAULT NULL )ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY LIST COLUMNS(sgender)( PARTITION p0 VALUES IN ('男'), PARTITION p1 VALUES IN ('女') );
如果試圖插入的值不在分區值列表中,插入語句將會報錯,將要匹配的值必須在分區值列表中找到。
6.COLUMNS分區
columns分區是對range,list分區的補充,彌補了后兩者只支持整型數分區(或者通過轉換為整型數),使得支持數據類型增加很多(所有整數類型,日期時間類型,字符類型),還支持多列分區。
columns分區可細分為range columns分區和list columns分區,多列分區示例:
create table range_columns( a int not null, b int not null ) partition by range columns(a,b)( partition p0 values less than(0,10), partition p1 values less than(10,20), partition p2 values less than(10,30), partition p3 values less than(maxvalue,maxvalue) );
在多列分區表上插入數據時,采用元組的比較,即多列排序,先根據field1排序,再根據field2排序,根據排序結果來來分區存儲數據。
mysql> insert into range_columns values (0,9); Query OK, 1 row affected (0.00 sec) mysql> select PARTITION_NAME,PARTITION_EXPRESSION,TABLE_ROWS from information_schema.partitions where table_schema=schema() and table_name='range_columns'; +----------------+----------------------+------------+ | PARTITION_NAME | PARTITION_EXPRESSION | TABLE_ROWS | +----------------+----------------------+------------+ | p0 | `a`,`b` | 1 | | p1 | `a`,`b` | 0 | | p2 | `a`,`b` | 1 | | p3 | `a`,`b` | 0 | +----------------+----------------------+------------+ 4 rows in set (0.01 sec)
7.HASH分區
HASH主要是為了讓數據在設定個數的分區中盡可能分布平均,執行哈希分區時,mysql會對分區鍵執行哈希函數,以確定數據放在哪個分區中。HASH分區分為常規HASH分區和線性HASH分區,前者使用取模算法,后者使用線性2的冪的運算規則。HASH分區示例如下,
create table hash_par( id int not null, name varchar(50) not null ) partition by hash(id) partitions 4; ----如果要指定為線性hash,可以使用partition by linear hash
插入一個id為31的數據,如下所示
mysql> insert into hash_par values (31,'zhumuxian'); Query OK, 1 row affected (0.00 sec) mysql> explain partitions select * from hash_par where id=31; +----+-------------+----------+------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | hash_par | p3 | ALL | NULL | NULL | NULL | NULL | 2 | Using where | +----+-------------+----------+------------+------+---------------+------+---------+------+------+-------------+ 1 row in set (0.00 sec)
HASH分區盡可能讓數據平均地分布在每個分區上,提高了查詢效率,但是增加了分區管理的代價,比如以前有5個分區,現在要加上一個分區,算法有mod(expr,5)變成(expr,6),原來5個分區的數據大部分要重新結算重新分區。雖然使用線性HASH分區會降低分區管理的代價,但是數據卻沒有常規HASH分布得那么均勻。
8.KEY分區
KEY分區類似與HASH分區,但是不能自定義表達式,不過支持分區鍵的類型很多,除卻Text,Blob等文本類型。KEY分區的設置如下:
create table hash_par( id int not null, name varchar(50) not null ) partition by key(id) partitions 4;
KEY分區的分區鍵可以不指定,默認會使用表的主鍵作為分區鍵,如果沒有主鍵,就使用唯一鍵,兩者都沒有的話就必須指定分區鍵了。
9.子分區(關鍵字subparttition)
RANGE分區或者LIST分區可以再次分割形成子分區,子分區可以是HASH分區或者KEY分區,例如:
create table users_par( id int not null, usrName varchar(50) not null, usrEmail varchar(50) not null, age int not null, birth date not null )engine=InnoDB default charset=utf8 partition by range(age) subpartition by hash(age) subpartitions 2( partition p0 values less than(20), partition p1 values less than(30), partition p2 values less than maxvalue );
10.分區時NULL值的處理
一般情況下,MYSQL把NULL當成零值后者最小值來處理。
在RANGE分區中,NULL會被當成最小值處理;LIST分區中,NULL值必須出現在枚舉值列表中,否則報錯;HASH/KEY分區中,NULL值被當成零值處理。
mysql> insert into student values (4010404,'zhumuxian','A1114',20,'男'); Query OK, 1 row affected (0.04 sec) mysql> insert into student values (4010405,'zhongzhaoxi','A1114',20,NULL); ERROR 1526 (HY000): Table has no partition for value from column_list mysql> select PARTITION_NAME,PARTITION_EXPRESSION,PARTITION_DESCRIPTION,TABLE_ROWS from information_schema.partitions where table_schema=schema() and table_name='student'; +----------------+----------------------+-----------------------+------------+ | PARTITION_NAME | PARTITION_EXPRESSION | PARTITION_DESCRIPTION | TABLE_ROWS | +----------------+----------------------+-----------------------+------------+ | p0 | `sgender` | '男' | 1 | | p1 | `sgender` | '女' | 0 | +----------------+----------------------+-----------------------+------------+ 2 rows in set (0.01 sec)
11.分區管理
RANGE和LIST分區在刪除,添加,重新定義等分區管理上非常類似,如下所示。
刪除分區(alter table tbl_name drop partition partition_name),分區被刪除后,該分區的數據一起被刪除。
mysql> alter table users_par drop partition p0; Query OK, 0 rows affected (0.24 sec) Records: 0 Duplicates: 0 Warnings: 0
添加分區(alter table tbl_name add partition)
mysql> alter table users_par add partition (partition p0 values less than (20)); ERROR 1481 (HY000): MAXVALUE can only be used in last partition definition --這里報錯是因為添加分區必須在原分區的最大端添加,在為LIST分區添加分區時,新分區的值列表的值不能包含任意一個現有分區中值列表中的值,否則報錯 mysql> alter table student add partition (partition p2 values in ('男')); ERROR 1495 (HY000): Multiple definition of same constant in list partitioning
重新定義分區(alter table tbl_name reorganize partition partition_name into),可以將一個分區拆開成多個,反之可以合並多個成一個或多個。
mysql> alter table users_par reorganize partition p1 into (partition p0 values less than (20),partition p1 values less t han(30)); Query OK, 1 row affected (0.05 sec) Records: 1 Duplicates: 0 Warnings: 0
需要注意的是:RANGE和LIST分區在重新定義時,只能重新定義相鄰的分區,不可以跳過分區,並且重新定義的分區區間必須和原分區區間一致,也不可以改變分區的類型。
HASH和KEY分區的管理
減少分區數量,使用coaleace關鍵字
mysql> alter table hash_par coalesce partition 2; Query OK, 1 row affected (0.04 sec) Records: 1 Duplicates: 0 Warnings: 0
增加分區數量
mysql> alter table hash_par add partition partitions 2; Query OK, 1 row affected (0.04 sec) Records: 1 Duplicates: 0 Warnings: 0
MySQL分區有利於查詢優化,快速刪除過期數據,提高查詢吞吐量等。