十、MySQL表分区

MySQL表分区介绍

  表分区是将⼀个表的数据按照⼀定的规则⽔平划分为不同的逻辑块,并分别进⾏物理存储,这个规则就叫做分区函数,可以有不同的分区规则。5.7可以通过show plugins语句查看当前MySQL是否⽀持表分区功能。

 +----------------------------+----------+--------------------+---------+---------+
 | Name                       | Status   | Type               | Library | License |
 +----------------------------+----------+--------------------+---------+---------+
 | BLACKHOLE                  | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
 | partition                  | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
 | FEDERATED                  | DISABLED | STORAGE ENGINE     | NULL    | GPL     |
 | ARCHIVE                    | ACTIVE   | STORAGE ENGINE     | NULL    | GPL     |
 | ngram                      | ACTIVE   | FTPARSER           | NULL    | GPL     |

MySQL8.0移除了show plugins⾥对partition的显示,但社区版本的表分区功能是默认开启的

mysql> CREATE TABLE employees ( id INT NOT NULL,
    ->  fname VARCHAR(30), lname VARCHAR(30),
    ->  hired DATE NOT NULL DEFAULT '1970-01-01',
    ->  separated DATE NOT NULL DEFAULT '9999-12-31',
    ->  job_code INT NOT NULL,
    ->  store_id INT NOT NULL )
    ->  PARTITION BY RANGE (store_id)
    ->  ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11),
    ->  PARTITION p2 VALUES LESS THAN (16), PARTITION p3 VALUES LESS THAN (21) );
Query OK, 0 rows affected (0.19 sec)

mysql> insert into employees values(1,'a','a',now(),now(),1,1),(2,'b','b',now(),now(),1,6);
Query OK, 2 rows affected, 4 warnings (0.07 sec)
Records: 2  Duplicates: 0  Warnings: 4

mysql> select * from employees;
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired      | separated  | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
|  1 | a     | a     | 2020-12-28 | 2020-12-28 |        1 |        1 |
|  2 | b     | b     | 2020-12-28 | 2020-12-28 |        1 |        6 |
+----+-------+-------+------------+------------+----------+----------+
2 rows in set (0.00 sec)

mysql> select * from employees partition (p0);
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired      | separated  | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
|  1 | a     | a     | 2020-12-28 | 2020-12-28 |        1 |        1 |
+----+-------+-------+------------+------------+----------+----------+
1 row in set (0.00 sec)

mysql> select * from employees partition (p1);
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired      | separated  | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
|  2 | b     | b     | 2020-12-28 | 2020-12-28 |        1 |        6 |
+----+-------+-------+------------+------------+----------+----------+
1 row in set (0.00 sec)

  但当表中含有主键或唯⼀键时,则每个被⽤作分区函数的字段必须是表中唯⼀键和主键的全部或⼀部分,否则就⽆法创建分区表。⽐如下⾯的表由于唯⼀键和主键没有相同的字段,所以⽆法创建表分区

mysql> CREATE TABLE tnp (
    ->  id INT NOT NULL AUTO_INCREMENT,
    ->  ref BIGINT NOT NULL,
    ->  name VARCHAR(255),
    ->  PRIMARY KEY pk (id),
    ->  UNIQUE KEY uk (ref) )
    ->  PARTITION BY RANGE (id)
    ->  ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN(11));
ERROR 1503 (HY000): A UNIQUE INDEX must include all columns in the table's partitioning function
mysql>  CREATE TABLE tnp (
    ->  id INT NOT NULL AUTO_INCREMENT,
    ->  ref BIGINT NOT NULL,
    ->  name VARCHAR(255),
    ->  PRIMARY KEY pk (id),
    ->  UNIQUE KEY uk (ref) )
    ->  PARTITION BY RANGE (ref)
    ->  ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN(11));
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

上述例⼦中删除唯⼀键,确保主键中的字段包含分区函数中的所有字段,创建成功

mysql>  CREATE TABLE tnp (
    ->  id INT NOT NULL AUTO_INCREMENT,
    ->  ref BIGINT NOT NULL,
    ->  name VARCHAR(255),
    ->  PRIMARY KEY pk (id))
    ->  PARTITION BY RANGE (id)
    ->  ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11));
Query OK, 0 rows affected (0.17 sec) 

或者将主键扩展为包含ref字段

mysql> CREATE TABLE tnp (id INT NOT NULL ,
    -> ref BIGINT NOT NULL,
    -> name VARCHAR(255),
    -> PRIMARY KEY pk (id,ref),
    -> UNIQUE KEY uk (ref) )
    -> PARTITION BY RANGE (ref)
    -> ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11));
Query OK, 0 rows affected (0.21 sec)

表分区的主要优势在于:
  可以允许在⼀个表⾥存储更多的数据,突破磁盘限制或者⽂件系统限制
  对于从表⾥将过期或历史的数据移除在表分区很容易实现,只要将对应的分区移除即可
  对某些查询和修改语句来说,可以⾃动将数据范围缩⼩到⼀个或⼏个表分区上,优化语句执⾏效率。⽽且可以通过显示指定表分区来执⾏语句,⽐如SELECT * FROM t PARTITION (p0,p1) WHERE c < 5

[root@vmware1 data]# cd test
[root@vmware1 test]# ls
 db.opt employees#P#p0.ibd employees#P#p2.ibd tnp.frm employees.frm employees#P#p1.ibd employees#P#p3.ibd tnp#P#p0.ibd

表分区类型分为:

  • RANGE表分区:范围表分区,按照⼀定的范围值来确定每个分区包含的数据
  • LIST表分区:列表表分区,按照⼀个⼀个确定的值来确定每个分区包含的数据
  • HASH表分区:哈希表分区,按照⼀个⾃定义的函数返回值来确定每个分区包含的数据
  • KEY表分区 :key表分区,与哈希表分区类似,只是⽤MySQL⾃⼰的HASH函数来确定每个分区包含的数据


范围表分区,按照⼀定的范围值来确定每个分区包含的数据,分区函数使⽤的字段必须只能是整数类型,分区的定义范围必须是连续的,且不能有重叠部分,通过使⽤VALUES LESS THAN来定义分区范围,表分区的范围定义是从⼩到⼤定义的

⽐如:

CREATE TABLE employees ( id INT NOT NULL,
 fname VARCHAR(30), lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT NOT NULL,
 store_id INT NOT NULL )
 PARTITION BY RANGE (store_id)
 ( PARTITION p0 VALUES LESS THAN (6), PARTITION p1 VALUES LESS THAN (11),
 PARTITION p2 VALUES LESS THAN (16), PARTITION p3 VALUES LESS THAN (21) );

  Store_id<6的数据被放在p0分区⾥,6<=store_id<10之间的数据被放在p1分区⾥,以此类推,当新插⼊的数据为(72, ‘Mitchell’, ‘Wilson’, ‘1998-06-25’, NULL, 13) 时,则新数据被插⼊到p2分区⾥,但当插⼊的数据的store_id为21时,由于没有分区去容纳此数据,所以会报错,我们需要修改⼀下表的定义
报错:

mysql> insert into employees values(4,'d','d',now(),now(),1,21);
 ERROR 1526 (HY000): Table has no partition for value 21

修改表的定义:

 CREATE TABLE employees ( id INT NOT NULL,
 fname VARCHAR(30), lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT NOT NULL,
 store_id INT NOT NULL )
 PARTITION BY RANGE (store_id)
 ( PARTITION p0 VALUES LESS THAN (6),PARTITION p1 VALUES LESS THAN (16),
 PARTITION p2 VALUES LESS THAN (11), PARTITION p3 VALUES LESS THAN (21));
 ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition ##表分区的范围定义不符合从⼩到⼤

 CREATE TABLE employees2( id INT NOT NULL,
 fname VARCHAR(30), lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT NOT NULL,
 store_id INT NOT NULL )
 PARTITION BY RANGE (name)
 ( PARTITION p0 VALUES LESS THAN ('a'), PARTITION p1 VALUES LESS THAN ('b'),
 PARTITION p2 VALUES LESS THAN ('c'), PARTITION p3 VALUES LESS THAN ('d'));
 ERROR 1697 (HY000): VALUES value for partition 'p0' must have typeINT ##表分区的范围定义不符合整形

CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT NOT NULL, store_id INT NOT NULL )
 PARTITION BY RANGE (store_id)
 ( PARTITION p0 VALUES LESS THAN (6),
 PARTITION p1 VALUES LESS THAN (11),
 PARTITION p2 VALUES LESS THAN (16),
 PARTITION p3 VALUES LESS THAN MAXVALUE
 );

  MAXVALUE关键词的作⽤是表示可能的最⼤值,所以任何store_id>=16的数据都会被写⼊到p3分区⾥。分区函数中也可以使⽤表达式,⽐如:

CREATE TABLE employees ( id INT NOT NULL, fname VARCHAR(30), lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01', separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT, store_id INT )
 PARTITION BY RANGE ( YEAR(separated) )
 ( PARTITION p0 VALUES LESS THAN (1991),
 PARTITION p1 VALUES LESS THAN (1996),
 PARTITION p2 VALUES LESS THAN (2001),
 PARTITION p3 VALUES LESS THAN MAXVALUE );

  对timestamp字段类型可以使⽤的表达式⽬前仅有unix_timestamp,其他的表达式都不允许

mysql> CREATE TABLE quarterly_report_status ( 
 report_id INT NOT NULL, 
 report_status VARCHAR(20) NOT NULL, 
 report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP)
 PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) )
 ( PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
 PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
 PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
 PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
 PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
 PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
 PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
 PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
 PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
 PARTITION p9 VALUES LESS THAN (MAXVALUE) ); 
Query OK, 0 rows affected (0.28 sec)

mysql> create table temp(tstamp timestamp) partition by range(year(tstamp))(partition p0 values less than(2017));
ERROR 1486 (HY000): Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed
mysql> create table temp(tstamp datetime) partition by range(year(tstamp))(partition p0 values less than(2017));
Query OK, 0 rows affected (0.07 sec)


列表表分区,按照⼀个⼀个确定的值来确定每个分区包含的数据,通过PARTITION BY LIST(expr)分区函数表达式必须返回整数,取值范围通过VALUES IN (value_list)定义

CREATE TABLE employees (
 id INT NOT NULL,
 fname VARCHAR(30),
 lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT, store_id INT )
 PARTITION BY LIST(store_id)
 ( PARTITION pNorth VALUES IN (3,5,6,9,17),
 PARTITION pEast VALUES IN (1,2,10,11,19,20),
 PARTITION pWest VALUES IN (4,12,13,14,18),
 PARTITION pCentral VALUES IN (7,8,15,16) ); 
Query OK, 0 rows affected (0.20 sec)

mysql> drop table employees;
Query OK, 0 rows affected (0.18 sec)

CREATE TABLE employees (
 id INT NOT NULL,
 fname VARCHAR(30),
 lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT, store_name varchar(20) )
 PARTITION BY LIST(store_name)
 ( PARTITION pNorth VALUES IN ('a','b'),
 PARTITION pEast VALUES IN ('c','d'));
ERROR 1697 (HY000): VALUES value for partition 'pNorth' must have type INT

对List表分区来说,没有MAXVALUE特殊值,所有的可能取值都需要再VALUES IN中包含,如果有未定义的取值则会报错

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.16 sec)

mysql> INSERT INTO h2 VALUES (3, 5);
ERROR 1526 (HY000): Table has no partition for value 3

同样,当有主键或者唯⼀键存在的情况下,分区函数字段需要包含在主键或唯⼀键中

mysql> CREATE TABLE employees (
 id INT NOT NULL primary key,
 fname VARCHAR(30),
 lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT,
 store_id int )
 PARTITION BY LIST(store_id)
 ( PARTITION pNorth VALUES IN (1,3),
 PARTITION pEast VALUES IN (2,4)); 
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

对range和list表分区来说,分区函数可以包含多个字段,分区多字段函数(column partition)所涉及的字段类型可以包括:

TINYINT, SMALLINT, MEDIUMINT, INT (INTEGER), and BIGINT.
DATE and DATETIME.
CHAR, VARCHAR, BINARY, and VARBINARY.
其他的字段类型都不⽀持

范围多字段分区函数与普通的范围分区函数的区别在于:
a) 字段类型多样化
b) 范围多字段分区函数不⽀持表达式,只能⽤字段名
c) 范围多字段分区函数⽀持⼀个或多个字段


每个column_list⾥的字段和value_list⾥的数值必须⼀⼀对应,数据类型也要⼀致
对范围多字段分区来说,有时⼀⾏数据的分区列表的第⼀个元素等于VALUES LESS THAN的值列表的第⼀个元素是会被插⼊到相应的分区

mysql> CREATE TABLE rcx (a INT, b INT,
 c CHAR(3), d INT)
 PARTITION BY RANGE COLUMNS(a,b,c)
 (PARTITION p0 VALUES LESS THAN (5,10,'ggg'),
 PARTITION p1 VALUES LESS THAN (10,20,'mmm'),
 PARTITION p2 VALUES LESS THAN (15,30,'sss'),
 PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE));
Query OK, 0 rows affected (0.13 sec)

mysql> insert into rcx values(4,5,'abc',1),(5,9,'abc',1),(4,11,'ggg',1),(5,11,'abc',1),(6,2, 'abc',1);
Query OK, 5 rows affected (0.07 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> select * from rcx partition (p0);
+------+------+------+------+
| a    | b    | c    | d    |
+------+------+------+------+
|    4 |    5 | abc  |    1 |
|    5 |    9 | abc  |    1 |
|    4 |   11 | ggg  |    1 |
+------+------+------+------+
3 rows in set (0.00 sec)

mysql> select * from rcx partition (p1);
+------+------+------+------+
| a    | b    | c    | d    |
+------+------+------+------+
|    5 |   11 | abc  |    1 |
|    6 |    2 | abc  |    1 |
+------+------+------+------+
2 rows in set (0.00 sec)

再⽐如创建如下的表分区:

mysql> CREATE TABLE rc1 ( a INT, b INT )
 PARTITION BY RANGE COLUMNS(a, b)
 ( PARTITION p0 VALUES LESS THAN (5, 12),
 PARTITION p3 VALUES LESS THAN (MAXVALUE, MAXVALUE) );
Query OK, 0 rows affected (0.18 sec)

mysql> INSERT INTO rc1 VALUES (5,10), (5,11), (5,12);
Query OK, 3 rows affected (0.09 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'rc1';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0             |          2 |
| p3             |          0 |
+----------------+------------+
2 rows in set (0.00 sec)

mysql> select * from rc1 partition (p0);
+------+------+
| a    | b    |
+------+------+
|    5 |   10 |
|    5 |   11 |
+------+------+
2 rows in set (0.00 sec)

mysql> select * from rc1 partition (p3);
+------+------+
| a    | b    |
+------+------+
|    5 |   12 |
+------+------+
1 row in set (0.00 sec)

## 此时,可以看出系统表的table_rows不是精确的,也不是实时统计的。需要要分析一下分区表
mysql> alter table rc1 analyze partition p3;
+----------+---------+----------+----------+
| Table    | Op      | Msg_type | Msg_text |
+----------+---------+----------+----------+
| test.rc1 | analyze | status   | OK       |
+----------+---------+----------+----------+
1 row in set (0.06 sec)

mysql> SELECT PARTITION_NAME,TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'rc1';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0             |          2 |
| p3             |          1 |
+----------------+------------+
2 rows in set (0.00 sec)

对多列对⽐来说:

mysql> SELECT (5,10) < (5,12), (5,11) < (5,12), (5,12) < (5,12);
+-----------------+-----------------+-----------------+
| (5,10) < (5,12) | (5,11) < (5,12) | (5,12) < (5,12) |
+-----------------+-----------------+-----------------+
|               1 |               1 |               0 |
+-----------------+-----------------+-----------------+
1 row in set (0.00 sec)

当然只要保证取值范围是增⻓的,表分区就能创建成功,⽐如:

CREATE TABLE rc4 ( a INT, b INT, c INT )
 PARTITION BY RANGE COLUMNS(a,b,c)
 ( PARTITION p0 VALUES LESS THAN (0,25,50),
 PARTITION p1 VALUES LESS THAN (10,20,100),
 PARTITION p2 VALUES LESS THAN (10,30,50),
 PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE) ); 
Query OK, 0 rows affected (0.14 sec)

但如果取值范围不是增⻓的,就会返回错误

CREATE TABLE rcf (a INT, b INT, c INT)
 PARTITION BY RANGE COLUMNS(a,b,c) (
 PARTITION p0 VALUES LESS THAN (0,25,50),
 PARTITION p1 VALUES LESS THAN (20,20,100),
 PARTITION p2 VALUES LESS THAN (10,30,50),
 PARTITION p3 VALUES LESS THAN (MAXVALUE,MAXVALUE,MAXVALUE));
ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition

对其他数据类型的⽀持:

mysql> CREATE TABLE employees_by_lname ( id INT NOT NULL, fname VARCHAR(30),
 lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT NOT NULL, store_id INT NOT NULL )
 PARTITION BY RANGE COLUMNS (lname)
 ( PARTITION p0 VALUES LESS THAN ('g'),
 PARTITION p1 VALUES LESS THAN ('m'),
 PARTITION p2 VALUES LESS THAN ('t'),
 PARTITION p3 VALUES LESS THAN (MAXVALUE) );
Query OK, 0 rows affected (0.16 sec)

mysql> drop table employees_by_lname;
Query OK, 0 rows affected (0.13 sec)

mysql> CREATE TABLE employees_by_lname ( id INT NOT NULL, fname VARCHAR(30),
 lname VARCHAR(30), hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT NOT NULL, store_id INT NOT NULL )
 PARTITION BY RANGE COLUMNS (hired)
 ( PARTITION p0 VALUES LESS THAN ('1970-01-01'),
 PARTITION p1 VALUES LESS THAN ('1980-01-01'),
 PARTITION p2 VALUES LESS THAN ('1990-01-01'),
 PARTITION p3 VALUES LESS THAN ('2000-01-01'),
 PARTITION p4 VALUES LESS THAN ('2010-01-01'),
 PARTITION p5 VALUES LESS THAN (MAXVALUE) );
Query OK, 0 rows affected (0.28 sec)

list列表多字段表分区,例如:你有一个在12个城市客户的业务, 为了销售和市场的目的, 你的组织每3个城市划分为一个区域针对LIST COLUMNS分区, 你可以基于城市的名称创建一个客户数据表并声明4个分区当你的客户在对应的这个区域:

CREATE TABLE customers_1
 ( first_name VARCHAR(25),
 last_name VARCHAR(25),
 street_1 VARCHAR(30),
 street_2 VARCHAR(30),
 city VARCHAR(15),
 renewal DATE )
 PARTITION BY LIST COLUMNS(city)
 ( PARTITION pRegion_1 VALUES IN('Oskarshamn', 'Högsby', 'Mönsterås'),
 PARTITION pRegion_2 VALUES IN('Vimmerby', 'Hultsfred', 'Västervik'),
 PARTITION pRegion_3 VALUES IN('Nässjö', 'Eksjö', 'Vetlanda'),
 PARTITION pRegion_4 VALUES IN('Uppvidinge', 'Alvesta', 'Växjo') );

使用日期分区

CREATE TABLE customers_2 (
    first_name VARCHAR(25),
    last_name VARCHAR(25),
    street_1 VARCHAR(30),
    street_2 VARCHAR(30),
    city VARCHAR(15),
    renewal DATE
)
PARTITION BY LIST COLUMNS(renewal) (
    PARTITION pWeek_1 VALUES IN('2010-02-01', '2010-02-02', '2010-02-03',
        '2010-02-04', '2010-02-05', '2010-02-06', '2010-02-07'),
    PARTITION pWeek_2 VALUES IN('2010-02-08', '2010-02-09', '2010-02-10',
        '2010-02-11', '2010-02-12', '2010-02-13', '2010-02-14'),
    PARTITION pWeek_3 VALUES IN('2010-02-15', '2010-02-16', '2010-02-17',
        '2010-02-18', '2010-02-19', '2010-02-20', '2010-02-21'),
    PARTITION pWeek_4 VALUES IN('2010-02-22', '2010-02-23', '2010-02-24',
        '2010-02-25', '2010-02-26', '2010-02-27', '2010-02-28')
);

但是这种情况在日期增长到非常大的时候是很复杂的, 所以这种还是使用RANGE 分区方式比较好


  按照⼀个⾃定义的函数返回值来确定每个分区包含的数据,这个⾃定义函数也可以仅仅是⼀个字段名字
  通过PARTITION BY HASH (expr)⼦句来表达哈希表分区,其中的expr表达式必须返回⼀个整数,基于分区个数的取模(%)运算。根据余数插⼊到指定的分区
  对哈希表分区来说只需要定义分区的个数,其他的事情由内部完成

mysql> CREATE TABLE employees (
 id INT NOT NULL,
 fname VARCHAR(30),
 lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT,
 store_id INT )
 PARTITION BY HASH(store_id)
 PARTITIONS 4; 
Query OK, 0 rows affected (0.15 sec)

mysql> insert into employees values(1,'a','a',now(),now(),1,1);
Query OK, 1 row affected, 2 warnings (0.07 sec)

mysql> insert into employees values(1,'a','a',now(),now(),1,2);
Query OK, 1 row affected, 2 warnings (0.02 sec)

mysql> insert into employees values(1,'a','a',now(),now(),1,3);
Query OK, 1 row affected, 2 warnings (0.05 sec)

mysql> insert into employees values(1,'a','a',now(),now(),1,4);
Query OK, 1 row affected, 2 warnings (0.04 sec)

mysql> insert into employees values(1,'a','a',now(),now(),1,5);
Query OK, 1 row affected, 2 warnings (0.03 sec)

mysql> select * from employees partition(p0);
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired      | separated  | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
|  1 | a     | a     | 2020-12-29 | 2020-12-29 |        1 |        4 |
+----+-------+-------+------------+------------+----------+----------+
1 row in set (0.00 sec)

mysql> select * from employees partition(p1);
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired      | separated  | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
|  1 | a     | a     | 2020-12-29 | 2020-12-29 |        1 |        1 |
|  1 | a     | a     | 2020-12-29 | 2020-12-29 |        1 |        5 |
+----+-------+-------+------------+------------+----------+----------+
2 rows in set (0.00 sec)

mysql> select * from employees partition(p2);
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired      | separated  | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
|  1 | a     | a     | 2020-12-29 | 2020-12-29 |        1 |        2 |
+----+-------+-------+------------+------------+----------+----------+
1 row in set (0.00 sec)

mysql> select * from employees partition(p3);
+----+-------+-------+------------+------------+----------+----------+
| id | fname | lname | hired      | separated  | job_code | store_id |
+----+-------+-------+------------+------------+----------+----------+
|  1 | a     | a     | 2020-12-29 | 2020-12-29 |        1 |        3 |
+----+-------+-------+------------+------------+----------+----------+
1 row in set (0.00 sec)

如果没有写明PARTITIONS字段,则默认为1,表达式可以是整数类型字段,也可以是⼀个函数,⽐如

CREATE TABLE employees (
 id INT NOT NULL,
 fname VARCHAR(30),
 lname VARCHAR(30),
 hired DATE NOT NULL DEFAULT '1970-01-01',
 separated DATE NOT NULL DEFAULT '9999-12-31',
 job_code INT, store_id INT )
 PARTITION BY HASH( YEAR(hired) )
 PARTITIONS 4;

⽐如:CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE) PARTITION BY HASH( YEAR(col3) ) PARTITIONS 4;
如果插⼊⼀条数据对应的col3为‘2005-09-15’时,则插⼊数据的分区计算⽅法为:

MOD(YEAR('2005-09-01'),4)
 = MOD(2005,4)
 = 1


  与哈希表分区类似,只不过哈希表分区依赖于⾃定义的函数,⽽key表分区的哈希算法是依赖MySQL本身,CREATE TABLE ... PARTITION BY KEY ()创建key表分区,括号⾥⾯可以包含0个或者多个字段,所引⽤的字段必须是主键或者主键的⼀部分,如果括号⾥⾯没有字段,则代表使⽤主键

CREATE TABLE k1 ( id INT NOT NULL PRIMARY KEY, name VARCHAR(20) )
 PARTITION BY KEY()
 PARTITIONS 2;

如果表中没有主键但有唯⼀键,则使⽤唯⼀键,但唯⼀键字段必须定义为not null,否则报错

mysql> CREATE TABLE k1 ( id INT, name VARCHAR(20), UNIQUE KEY (id) ) PARTITION BY KEY() PARTITIONS 2;
ERROR 1488 (HY000): Field in list of fields for partition function not found in table
mysql> CREATE TABLE k1 ( id INT NOT NULL, name VARCHAR(20), UNIQUE KEY (id) ) PARTITION BY KEY() PARTITIONS 2;
Query OK, 0 rows affected (0.09 sec)

所引⽤的字段未必必须是整数类型,其他的类型也可以使⽤,⽐如:

mysql> CREATE TABLE tm1 ( s1 CHAR(32) PRIMARY KEY )
 PARTITION BY KEY(s1)
 PARTITIONS 10;
Query OK, 0 rows affected (0.27 sec)

⼦表分区,是在表分区的基础上再创建表分区的概念,每个表分区下的⼦表分区个数必须⼀致,⽐如:

mysql> 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 );
Query OK, 0 rows affected (0.26 sec)

ts表拥有三个范围分区,同时每个分区都各⾃有两个⼦分区,所以总共有6个分区

⼦表分区必须是范围/列表分区+哈希/key⼦表分区的组合
⼦表分区也可以显示的指定⼦表分区的名字,⽐如:

mysql> CREATE TABLE ts (id INT, purchased DATE)
 PARTITION BY RANGE( YEAR(purchased) )
 SUBPARTITION BY HASH( TO_DAYS(purchased) )
 ( PARTITION p0 VALUES LESS THAN (1990)
 ( SUBPARTITION s0, SUBPARTITION s1 ),
 PARTITION p1 VALUES LESS THAN (2000)
 ( SUBPARTITION s2, SUBPARTITION s3 ),
 PARTITION p2 VALUES LESS THAN MAXVALUE
 ( SUBPARTITION s4, SUBPARTITION s5 ) );
Query OK, 0 rows affected (0.22 sec)

MySQL表分区对Null值处理

不同的表分区对NULL值的处理⽅式不同
对范围表分区来说,如果插⼊的是NULL值,则将数据放到最⼩的分区表⾥

mysql> CREATE TABLE t1 ( c1 INT, c2 VARCHAR(20) )
 PARTITION BY RANGE(c1)
 ( PARTITION p0 VALUES LESS THAN (0),
 PARTITION p1 VALUES LESS THAN (10),
 PARTITION p2 VALUES LESS THAN MAXVALUE );
Query OK, 0 rows affected (0.20 sec)

mysql> INSERT INTO t1 VALUES (NULL, 'mothra');
Query OK, 1 row affected (0.02 sec)

mysql> select * from t1 partition(p0);
+------+--------+
| c1   | c2     |
+------+--------+
| NULL | mothra |
+------+--------+
1 row in set (0.00 sec)

对list表分区来说,⽀持NULL值的唯⼀情况就是某个分区的允许值中包含NULL

mysql> CREATE TABLE ts1 (c1 INT, c2 VARCHAR(20))
 PARTITION BY LIST(c1)
 (PARTITION p0 VALUES IN (0, 3, 6),
 PARTITION p1 VALUES IN (1, 4, 7),
 PARTITION p2 VALUES IN (2, 5, 8));
Query OK, 0 rows affected (0.17 sec)

mysql> INSERT INTO ts1 VALUES (9, 'mothra');
ERROR 1526 (HY000): Table has no partition for value 9
mysql> INSERT INTO ts1 VALUES (NULL, 'mothra');
ERROR 1526 (HY000): Table has no partition for value NULL

mysql> CREATE TABLE ts2 (c1 INT, c2 VARCHAR(20))
 PARTITION BY LIST(c1)
 (PARTITION p0 VALUES IN (0, 3, 6),
 PARTITION p1 VALUES IN (1, 4, 7),
 PARTITION p2 VALUES IN (2, 5, 8),
 PARTITION p3 VALUES IN (NULL));
Query OK, 0 rows affected (0.19 sec)

mysql> CREATE TABLE ts3 (c1 INT, c2 VARCHAR(20))
 PARTITION BY LIST(c1)
 (PARTITION p0 VALUES IN (0, 3, 6),
 PARTITION p1 VALUES IN (1, 4, 7, NULL),
 PARTITION p2 VALUES IN (2, 5, 8));
Query OK, 0 rows affected (0.14 sec)

mysql> INSERT INTO ts2 VALUES (NULL, 'mothra');
Query OK, 1 row affected (0.03 sec)

mysql> INSERT INTO ts3 VALUES (NULL, 'mothra');
Query OK, 1 row affected (0.02 sec)

对哈希表分区和Key表分区来说,NULL值会被当成0值对待

mysql> CREATE TABLE th ( c1 INT, c2 VARCHAR(20) )
 PARTITION BY HASH(c1)
 PARTITIONS 2;
Query OK, 0 rows affected (0.13 sec)

mysql> INSERT INTO th VALUES (NULL, 'mothra'), (0, 'gigan');
Query OK, 2 rows affected (0.05 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from th partition(p0);
+------+--------+
| c1   | c2     |
+------+--------+
| NULL | mothra |
|    0 | gigan  |
+------+--------+
2 rows in set (0.00 sec)

MySQL表分区管理

通过alter table命令可以执⾏增加,删除,重新定义,合并或者拆分表分区的管理动作
对范围表分区和列表表分区来说,删除⼀个表分区命令如下:

mysql> CREATE TABLE tr
 (id INT,
 name VARCHAR(50),
 purchased DATE)
 PARTITION BY RANGE( YEAR(purchased) )
 ( PARTITION p0 VALUES LESS THAN (1990),
 PARTITION p1 VALUES LESS THAN (1995),
 PARTITION p2 VALUES LESS THAN (2000),
 PARTITION p3 VALUES LESS THAN (2005),
 PARTITION p4 VALUES LESS THAN (2010),
 PARTITION p5 VALUES LESS THAN (2015) ); 
Query OK, 0 rows affected (0.26 sec)

mysql> insert into tr values(1, 'abc','1999-12-21');
Query OK, 1 row affected (0.09 sec)

mysql> select * from tr partition(p2);
+------+------+------------+
| id   | name | purchased  |
+------+------+------------+
|    1 | abc  | 1999-12-21 |
+------+------+------------+
1 row in set (0.00 sec)

mysql> ALTER TABLE tr DROP PARTITION p2;
Query OK, 0 rows affected (0.13 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from tr partition(p2);
ERROR 1735 (HY000): Unknown partition 'p2' in table 'tr'

删除表分区的动作不光会把分区删掉,也会把表分区⾥原来的数据给删除掉

mysql> show create table tr;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tr    | CREATE TABLE `tr` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `purchased` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY RANGE (year(`purchased`))
(PARTITION p0 VALUES LESS THAN (1990) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (1995) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (2005) ENGINE = InnoDB,
 PARTITION p4 VALUES LESS THAN (2010) ENGINE = InnoDB,
 PARTITION p5 VALUES LESS THAN (2015) ENGINE = InnoDB) */ |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM tr WHERE purchased BETWEEN '1995-01-01' AND '1999-12-31';                                                                                                                                                                                                 
Empty set (0.00 sec)

在原分区上增加⼀个表分区可以通过alter table … add partition语句来完成

mysql> CREATE TABLE members (
 id INT, fname VARCHAR(25),
 lname VARCHAR(25),
 dob DATE ) 
 PARTITION BY RANGE( YEAR(dob) )
 ( PARTITION p0 VALUES LESS THAN (1980),
 PARTITION p1 VALUES LESS THAN (1990),
 PARTITION p2 VALUES LESS THAN (2000) );
Query OK, 0 rows affected (0.14 sec)

mysql> ALTER TABLE members ADD PARTITION (PARTITION p3 VALUES LESS THAN (2010));
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into members values(1,'a','b','1978-01-01');
Query OK, 1 row affected (0.03 sec)

但对范围表分区来说,增加的表分区必须在尾部增加,在头部或者在中间增加都会失败:

mysql> ALTER TABLE members ADD PARTITION ( PARTITION n VALUES LESS THAN (1970));
ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition

为解决这个问题,可以使⽤REORGANIZE命令:

mysql> show create table members;
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| members | CREATE TABLE `members` (
  `id` int(11) DEFAULT NULL,
  `fname` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `lname` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `dob` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY RANGE (year(`dob`))
(PARTITION p0 VALUES LESS THAN (1980) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (1990) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (2010) ENGINE = InnoDB) */ |
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ALTER TABLE members REORGANIZE PARTITION p0 INTO
  ( PARTITION n0 VALUES LESS THAN (1970), PARTITION n1 VALUES LESS THAN (1980) );
Query OK, 0 rows affected (0.17 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table members;
+---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
+---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| members | CREATE TABLE `members` (
  `id` int(11) DEFAULT NULL,
  `fname` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `lname` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `dob` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY RANGE (year(`dob`))
(PARTITION n0 VALUES LESS THAN (1970) ENGINE = InnoDB,
 PARTITION n1 VALUES LESS THAN (1980) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (1990) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (2010) ENGINE = InnoDB) */ |
+---------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>  select * from members;
+------+-------+-------+------------+
| id   | fname | lname | dob        |
+------+-------+-------+------------+
|    1 | a     | b     | 1978-01-01 |
+------+-------+-------+------------+
1 row in set (0.00 sec)

mysql> select * from members partition(n1);
+------+-------+-------+------------+
| id   | fname | lname | dob        |
+------+-------+-------+------------+
|    1 | a     | b     | 1978-01-01 |
+------+-------+-------+------------+
1 row in set (0.00 sec)

对列表表分区来说,只要新增加的分区对应的值在之前的表分区中没有出现过,就可以通过alter table… add partition来增加

mysql> CREATE TABLE tt ( id INT, data INT ) PARTITION BY LIST(data)
 ( PARTITION p0 VALUES IN (5, 10, 15),
 PARTITION p1 VALUES IN (6, 12, 18) );
Query OK, 0 rows affected (0.17 sec)

mysql> ALTER TABLE tt ADD PARTITION (PARTITION p2 VALUES IN (7, 14, 21));
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0

当然,也可以通过REORGANIZE命令将之前的多个分区合并成⼀个或⼏个分区,但要保持分区值⼀致:

mysql> ALTER TABLE members REORGANIZE PARTITION n0,n1 INTO ( PARTITION p0 VALUES LESS THAN (1970) );
ERROR 1520 (HY000): Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range
mysql> ALTER TABLE members REORGANIZE PARTITION n0,n1 INTO ( PARTITION p0 VALUES LESS THAN (1985) );
ERROR 1520 (HY000): Reorganize of range partitions cannot change total ranges except for last partition where it can extend the range
mysql> ALTER TABLE members REORGANIZE PARTITION n0,n1 INTO ( PARTITION p0 VALUES LESS THAN (1980) );
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table members;
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| members | CREATE TABLE `members` (
  `id` int(11) DEFAULT NULL,
  `fname` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `lname` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `dob` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY RANGE (year(`dob`))
(PARTITION p0 VALUES LESS THAN (1980) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (1990) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (2010) ENGINE = InnoDB) */ |
+---------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

更复杂的⽐如将多个分区重组成多个分区:

mysql> ALTER TABLE members REORGANIZE PARTITION p0,p1,p2,p3 INTO ( PARTITION m0 VALUES LESS
    -> THAN (1980), PARTITION m1 VALUES LESS THAN (2010));
Query OK, 0 rows affected (0.18 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table members;
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                |
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| members | CREATE TABLE `members` (
  `id` int(11) DEFAULT NULL,
  `fname` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `lname` varchar(25) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `dob` date DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY RANGE (year(`dob`))
(PARTITION m0 VALUES LESS THAN (1980) ENGINE = InnoDB,
 PARTITION m1 VALUES LESS THAN (2010) ENGINE = InnoDB) */ |
+---------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

对列表分区来说,重新组织的分区必须是相邻的分区

mysql> show create table tt;
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                      |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tt    | CREATE TABLE `tt` (
  `id` int(11) DEFAULT NULL,
  `data` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY LIST (`data`)
(PARTITION p0 VALUES IN (5,10,15) ENGINE = InnoDB,
 PARTITION p1 VALUES IN (6,12,18) ENGINE = InnoDB,
 PARTITION p2 VALUES IN (7,14,21) ENGINE = InnoDB) */ |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ALTER TABLE tt ADD PARTITION (PARTITION np VALUES IN (4, 8));
Query OK, 0 rows affected (0.15 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE tt REORGANIZE PARTITION p1,np INTO
  ( PARTITION p1 VALUES IN (6, 18), PARTITION np VALUES in (4, 8, 12) );
ERROR 1519 (HY000): When reorganizing a set of partitions they must be in consecutive order
mysql> show create table tt;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                     |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| tt    | CREATE TABLE `tt` (
  `id` int(11) DEFAULT NULL,
  `data` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY LIST (`data`)
(PARTITION p0 VALUES IN (5,10,15) ENGINE = InnoDB,
 PARTITION p1 VALUES IN (6,12,18) ENGINE = InnoDB,
 PARTITION p2 VALUES IN (7,14,21) ENGINE = InnoDB,
 PARTITION np VALUES IN (4,8) ENGINE = InnoDB) */ |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> insert into tt values(1,10),(2,5);
Query OK, 2 rows affected (0.04 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> select * from tt;
+------+------+
| id   | data |
+------+------+
|    1 |   10 |
|    2 |    5 |
+------+------+
2 rows in set (0.00 sec)

如果表⾥已有的数据在新重组的分区中没有指定的值,则数据会丢失

mysql> ALTER TABLE tt REORGANIZE PARTITION p0,p1 INTO ( PARTITION p0 VALUES IN (6, 18), PARTITION p1
    -> VALUES in (5,15));
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from tt;
+------+------+
| id   | data |
+------+------+
|    2 |    5 |
+------+------+
1 row in set (0.00 sec)

  对哈希表分区和KEY表分区的管理⼿段与范围和列表表分区完全不同,⽐如不能删除表分区,但可以通过ALTER TABLE ... COALESCE PARTITION语句合并表分区,其partition后⾯的数字代表缩减的个数,⽽不是缩减到的个数

mysql> CREATE TABLE clients ( id INT, fname VARCHAR(30), lname VARCHAR(30), signed DATE )
 PARTITION BY HASH( MONTH(signed) )
 PARTITIONS 12;
Query OK, 0 rows affected (0.41 sec)

mysql> insert into clients values(1,'a','a','2017-01-01'),(2,'a','a','2017-02-01'),(3,'a','a','2017-03-01'),(4,'a','a','2017-04-01');
Query OK, 4 rows affected (0.03 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE clients COALESCE PARTITION 4;
Query OK, 0 rows affected (0.68 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> analyze table clients;
+--------------+---------+----------+----------+
| Table        | Op      | Msg_type | Msg_text |
+--------------+---------+----------+----------+
| test.clients | analyze | status   | OK       |
+--------------+---------+----------+----------+
1 row in set (0.17 sec)

mysql> select partition_name,table_rows from information_schema.partitions where table_name='clients';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0             |          0 |
| p1             |          1 |
| p2             |          1 |
| p3             |          1 |
| p4             |          1 |
| p5             |          0 |
| p6             |          0 |
| p7             |          0 |
+----------------+------------+
8 rows in set (0.00 sec)

对于哈希表分区和key表分区,如果是增加表分区,则可以使⽤add partition语句

mysql> ALTER TABLE clients ADD PARTITION PARTITIONS 6;
Query OK, 0 rows affected (0.76 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> analyze table clients;
+--------------+---------+----------+----------+
| Table        | Op      | Msg_type | Msg_text |
+--------------+---------+----------+----------+
| test.clients | analyze | status   | OK       |
+--------------+---------+----------+----------+
1 row in set (0.13 sec)

mysql> select partition_name,table_rows from information_schema.partitions where table_name='clients';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0             |          0 |
| p1             |          1 |
| p10            |          0 |
| p11            |          0 |
| p12            |          0 |
| p13            |          0 |
| p2             |          1 |
| p3             |          1 |
| p4             |          1 |
| p5             |          0 |
| p6             |          0 |
| p7             |          0 |
| p8             |          0 |
| p9             |          0 |
+----------------+------------+
14 rows in set (0.01 sec)

  对分区表可以通过ALTER TABLE pt EXCHANGE PARTITION p WITH TABLE nt命令将⼀个分区或者是⼦分区的数据与普通的表的数据相互交换,其本身的表结构不会变化
  交换的分区表和⽬标表必须结构完全相同,包括字段,类型,索引,存储引擎必须完全样

mysql> CREATE TABLE e (
 id INT NOT NULL,
 fname VARCHAR(30),
 lname VARCHAR(30) )
 PARTITION BY RANGE (id)
 ( PARTITION p0 VALUES LESS THAN (50),
 PARTITION p1 VALUES LESS THAN (100),
 PARTITION p2 VALUES LESS THAN (150),
 PARTITION p3 VALUES LESS THAN (MAXVALUE) );
Query OK, 0 rows affected (0.18 sec)

mysql> CREATE TABLE e2 LIKE e;
Query OK, 0 rows affected (0.17 sec)

mysql> insert into e(id,fname) values(10,'a'),(20,'b'),(170,'c'),(180,'d'),(190,'e');
Query OK, 5 rows affected (0.05 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE e2 REMOVE PARTITIONING;
Query OK, 0 rows affected (0.22 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2;
Query OK, 0 rows affected (0.13 sec)

mysql> SELECT PARTITION_NAME, TABLE_ROWS
  FROM INFORMATION_SCHEMA.PARTITIONS
  WHERE TABLE_NAME = 'e';
+----------------+------------+
| PARTITION_NAME | TABLE_ROWS |
+----------------+------------+
| p0             |          0 |
| p1             |          0 |
| p2             |          0 |
| p3             |          3 |
+----------------+------------+
4 rows in set (0.01 sec)

mysql> select * from e2;
+----+-------+-------+
| id | fname | lname |
+----+-------+-------+
| 10 | a     | NULL  |
| 20 | b     | NULL  |
+----+-------+-------+
2 rows in set (0.00 sec)

mysql> ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2;##再次执⾏后数据交换回来
Query OK, 0 rows affected (0.08 sec)

mysql> select * from e;
+-----+-------+-------+
| id  | fname | lname |
+-----+-------+-------+
|  10 | a     | NULL  |
|  20 | b     | NULL  |
| 170 | c     | NULL  |
| 180 | d     | NULL  |
| 190 | e     | NULL  |
+-----+-------+-------+
5 rows in set (0.01 sec)

mysql> select * from e2;
Empty set (0.00 sec)

mysql> create table e3(id int, fname varchar(30),lname2 varchar(30));
Query OK, 0 rows affected (0.14 sec)

mysql> alter table e exchange partition p3 with table e3;
ERROR 1736 (HY000): Tables have different definitions

mysql> drop table e3;
Query OK, 0 rows affected (0.07 sec)

mysql> create table e3(id int not null, fname varchar(30),lname varchar(32));
Query OK, 0 rows affected (0.10 sec)

mysql> alter table e exchange partition p3 with table e3;
ERROR 1736 (HY000): Tables have different definitions

  执⾏exchange命令时,⽬标表⾥不⼀定是空数据,如果有数据需要保证⾥⾯的数据符合表分区的条件,否则只能⽤WITHOUT VALIDATION来跳过验证环节

mysql> INSERT INTO e2 VALUES (51, "Ellen", "McDonald");
Query OK, 1 row affected (0.07 sec)

mysql> ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLEe2;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'TABLEe2' at line 1
mysql> ALTER TABLE e EXCHANGE PARTITION p0 WITH TABLE e2 WITHOUT VALIDATION;
Query OK, 0 rows affected (0.08 sec)

对⼦表分区也可以执⾏exchange命令:

mysql> CREATE TABLE es (
 id INT NOT NULL,
 fname VARCHAR(30),
 lname VARCHAR(30) )
 PARTITION BY RANGE (id)
 SUBPARTITION BY KEY (lname)
 SUBPARTITIONS 2 (
  PARTITION p0 VALUES LESS THAN (50),
  PARTITION p1 VALUES LESS THAN (100),
  PARTITION p2 VALUES LESS THAN (150),
  PARTITION p3 VALUES LESS THAN (MAXVALUE) );
Query OK, 0 rows affected (0.34 sec)

mysql> CREATE TABLE es2 LIKE es;
Query OK, 0 rows affected (0.27 sec)

mysql> ALTER TABLE es2 REMOVE PARTITIONING;
Query OK, 0 rows affected (0.40 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE es EXCHANGE PARTITION p3sp0 WITH TABLE es2;
Query OK, 0 rows affected (0.14 sec)

当表是有⼦表分区时,只能exchange⼀个⼦表分区,⽽不能交换整个分区

mysql> SELECT PARTITION_NAME, SUBPARTITION_NAME, TABLE_ROWS FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME = 'es';
+----------------+-------------------+------------+
| PARTITION_NAME | SUBPARTITION_NAME | TABLE_ROWS |
+----------------+-------------------+------------+
| p0             | p0sp0             |          0 |
| p0             | p0sp1             |          0 |
| p1             | p1sp0             |          0 |
| p1             | p1sp1             |          0 |
| p2             | p2sp0             |          0 |
| p2             | p2sp1             |          0 |
| p3             | p3sp0             |          0 |
| p3             | p3sp1             |          0 |
+----------------+-------------------+------------+
8 rows in set (0.00 sec)

mysql> ALTER TABLE es EXCHANGE PARTITION p3 WITH TABLE es2;
ERROR 1734 (HY000): Subpartitioned table, use subpartition instead of partition

当需要去除分区碎⽚是,可以执⾏rebuild命令,相当于删除数据之后重新插⼊

mysql> ALTER TABLE t1 REBUILD PARTITION p0, p1;
Query OK, 0 rows affected (0.23 sec)
Records: 0  Duplicates: 0  Warnings: 0

也可以执⾏OPTIMIZE命令回收分区中未使⽤的空间和重新获取统计资料

mysql> ALTER TABLE t1 OPTIMIZE PARTITION p0, p1;
+---------+----------+----------+---------------------------------------------------------------------------------------------+
| Table   | Op       | Msg_type | Msg_text                                                                                    |
+---------+----------+----------+---------------------------------------------------------------------------------------------+
| test.t1 | optimize | note     | Table does not support optimize on partitions. All partitions will be rebuilt and analyzed. |
| test.t1 | optimize | status   | OK                                                                                          |
+---------+----------+----------+---------------------------------------------------------------------------------------------+
2 rows in set (0.35 sec)

Analyzing partitions命令重新收集分区统计资料

mysql> show create table t1;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                           |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
  `c1` int(11) DEFAULT NULL,
  `c2` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY RANGE (`c1`)
(PARTITION p0 VALUES LESS THAN (0) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (10) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> ALTER TABLE t1 ANALYZE PARTITION p3;
+---------+---------+----------+----------------------------------------+
| Table   | Op      | Msg_type | Msg_text                               |
+---------+---------+----------+----------------------------------------+
| test.t1 | analyze | Error    | Error in list of partitions to test.t1 |
| test.t1 | analyze | status   | Operation failed                       |
+---------+---------+----------+----------------------------------------+
2 rows in set (0.01 sec)

mysql> ALTER TABLE t1 ANALYZE PARTITION p2;
+---------+---------+----------+----------+
| Table   | Op      | Msg_type | Msg_text |
+---------+---------+----------+----------+
| test.t1 | analyze | status   | OK       |
+---------+---------+----------+----------+
1 row in set (0.02 sec)

Repairing partitions命令修复异常的分区

mysql> ALTER TABLE t1 REPAIR PARTITION p0,p1;
+---------+--------+----------+----------+
| Table   | Op     | Msg_type | Msg_text |
+---------+--------+----------+----------+
| test.t1 | repair | status   | OK       |
+---------+--------+----------+----------+
1 row in set (0.01 sec)

Checking partitions命令检查分区中数据或者索引数据是否损坏

mysql> ALTER TABLE t1 CHECK PARTITION p1;
+---------+-------+----------+----------+
| Table   | Op    | Msg_type | Msg_text |
+---------+-------+----------+----------+
| test.t1 | check | status   | OK       |
+---------+-------+----------+----------+
1 row in set (0.00 sec)

ALTER TABLE ... TRUNCATE PARTITION命令⽤来删除分区中的所有数据

mysql> select * from e partition(p0);
+----+-------+----------+
| id | fname | lname    |
+----+-------+----------+
| 51 | Ellen | McDonald |
+----+-------+----------+
1 row in set (0.00 sec)

mysql> alter table e truncate partition p0;
Query OK, 0 rows affected (0.16 sec)

mysql> select * from e partition(p0);
Empty set (0.00 sec)

获取表的分区信息有如下⼏种:

  • 通过show create table命令:
mysql> show create table e;
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| e     | CREATE TABLE `e` (
  `id` int(11) NOT NULL,
  `fname` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `lname` varchar(30) COLLATE utf8mb4_general_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
/*!50100 PARTITION BY RANGE (`id`)
(PARTITION p0 VALUES LESS THAN (50) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (100) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (150) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
  • 通过show table status命令来查看表是否是分区表,Create_options项
mysql> show table status like 'e';
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+--------------------+----------+----------------+---------+
| Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time         | Update_time         | Check_time | Collation          | Checksum | Create_options | Comment |
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+--------------------+----------+----------------+---------+
| e    | InnoDB |      10 | Dynamic    |    3 |          21845 |       65536 |               0 |            0 |         0 |           NULL | 2020-12-30 20:05:04 | 2020-12-30 20:05:14 | NULL       | utf8mb4_general_ci |     NULL | partitioned    |         |
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+---------------------+------------+--------------------+----------+----------------+---------+
1 row in set (0.01 sec)
  • 通过information_schema.partitions系统表来查看分区表的具体信息
mysql> select * from information_schema.partitions where table_name='e';
+---------------+--------------+------------+----------------+-------------------+----------------------------+-------------------------------+------------------+---------------------+----------------------+-------------------------+-----------------------+------------+----------------+-------------+-----------------+--------------+-----------+---------------------+---------------------+------------+----------+-------------------+-----------+-----------------+
| TABLE_CATALOG | TABLE_SCHEMA | TABLE_NAME | PARTITION_NAME | SUBPARTITION_NAME | PARTITION_ORDINAL_POSITION | SUBPARTITION_ORDINAL_POSITION | PARTITION_METHOD | SUBPARTITION_METHOD | PARTITION_EXPRESSION | SUBPARTITION_EXPRESSION | PARTITION_DESCRIPTION | TABLE_ROWS | AVG_ROW_LENGTH | DATA_LENGTH | MAX_DATA_LENGTH | INDEX_LENGTH | DATA_FREE | CREATE_TIME         | UPDATE_TIME         | CHECK_TIME | CHECKSUM | PARTITION_COMMENT | NODEGROUP | TABLESPACE_NAME |
+---------------+--------------+------------+----------------+-------------------+----------------------------+-------------------------------+------------------+---------------------+----------------------+-------------------------+-----------------------+------------+----------------+-------------+-----------------+--------------+-----------+---------------------+---------------------+------------+----------+-------------------+-----------+-----------------+
| def           | test         | e          | p0             | NULL              |                          1 |                          NULL | RANGE            | NULL                | `id`                 | NULL                    | 50                    |          0 |              0 |       16384 |               0 |            0 |         0 | 2020-12-30 20:05:04 | NULL                | NULL       |     NULL |                   | default   | NULL            |
| def           | test         | e          | p1             | NULL              |                          2 |                          NULL | RANGE            | NULL                | `id`                 | NULL                    | 100                   |          0 |              0 |       16384 |               0 |            0 |         0 | 2020-12-30 20:05:04 | NULL                | NULL       |     NULL |                   | default   | NULL            |
| def           | test         | e          | p2             | NULL              |                          3 |                          NULL | RANGE            | NULL                | `id`                 | NULL                    | 150                   |          0 |              0 |       16384 |               0 |            0 |         0 | 2020-12-30 20:05:04 | NULL                | NULL       |     NULL |                   | default   | NULL            |
| def           | test         | e          | p3             | NULL              |                          4 |                          NULL | RANGE            | NULL                | `id`                 | NULL                    | MAXVALUE              |          3 |           5461 |       16384 |               0 |            0 |         0 | 2020-12-30 20:05:04 | 2020-12-30 20:05:14 | NULL       |     NULL |                   | default   | NULL            |
+---------------+--------------+------------+----------------+-------------------+----------------------------+-------------------------------+------------------+---------------------+----------------------+-------------------------+-----------------------+------------+----------------+-------------+-----------------+--------------+-----------+---------------------+---------------------+------------+----------+-------------------+-----------+-----------------+
4 rows in set (0.00 sec)

MySQL表分区修剪

表分区修剪是MySQL优化的⼀种,其核⼼就是只扫描需要的分区
⽐如:

mysql> CREATE TABLE t1 (
 fname VARCHAR(50) NOT NULL,
 lname VARCHAR(50) NOT NULL,
 region_code TINYINT UNSIGNED NOT NULL,
 dob DATE NOT NULL )
 PARTITION BY RANGE( region_code )
 ( PARTITION p0 VALUES LESS THAN (64),
 PARTITION p1 VALUES LESS THAN (128),
 PARTITION p2 VALUES LESS THAN (192),
 PARTITION p3 VALUES LESS THAN MAXVALUE );
Query OK, 0 rows affected (0.14 sec)

mysql> explain SELECT fname, lname, region_code, dob
FROM t1
WHERE region_code > 125 AND region_code < 130;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | p1,p2      | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

此查询只需要扫描P1和P2两个分区就能得到结果,从⽽获得额外的性能提升
不光是select语句可以被使⽤表分区修剪,update和delete语句也可以使⽤

MySQL表分区修剪

表分区选择和表分区修剪类似,只不过修剪是⾃动实现的,⽽表分区选择是现实的指定分区范围
表分区选择不仅⽀持select语句,也⽀持update,insert,delete等语句

CREATE TABLE employees (
 id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 fname VARCHAR(25) NOT NULL,
 lname VARCHAR(25) NOT NULL,
 store_id INT NOT NULL,
 department_id INT NOT NULL )
 PARTITION BY RANGE(id)
 ( PARTITION p0 VALUES LESS THAN (5),
 PARTITION p1 VALUES LESS THAN (10),
 PARTITION p2 VALUES LESS THAN (15),
 PARTITION p3 VALUES LESS THAN MAXVALUE );

mysql> SELECT * FROM employees PARTITION (p1); # 从分区p1下查找
 +----+-------+--------+----------+---------------+
 | id | fname | lname  | store_id | department_id |
 +----+-------+--------+----------+---------------+
 | 5  | Mary  | Jones  | 1        | 1             |
 | 6  | Linda | Black  | 2        | 3             |
 | 7  | Ed    | Jones  | 2        | 1             |
 | 8  | June  | Wilson | 3        | 1             |
 | 9  | Andy  | Smith  | 1        | 3             |
 +----+-------+--------+----------+---------------+

mysql> SELECT * FROM employees PARTITION (p0, p2) WHERE lname LIKE 'S%'; # 从分区p0、p2下查找
 +----+-------+-------+----------+---------------+
 | id | fname | lname | store_id | department_id |
 +----+-------+-------+----------+---------------+
 | 4  | Jim   | Smith | 2        | 4             |
 | 11 | Jill  | Stone | 1        | 4             |
 +----+-------+-------+----------+---------------+

mysql> SELECT e.id AS 'Employee ID',
 CONCAT(e.fname, ' ', e.lname) AS Name,
 s.city AS City,
 d.name AS department
 FROM employees AS e
 JOIN stores PARTITION (p1) AS s ON e.store_id=s.id
 JOIN departments PARTITION (p0) AS d ON e.department_id=d.id
 ORDER BY e.lname;
 +-------------+---------------+-----------+------------+
 | Employee ID | Name          | City      | department |
 +-------------+---------------+-----------+------------+
 | 14          | Fred Goldberg | Bellingen | Delivery   |
 | 5           | Mary Jones    | Nambucca  | Sales      |
 | 17          | Mark Morgan   | Bellingen | Delivery   |
 | 9           | Andy Smith    | Nambucca  | Delivery   |
 | 8           | June Wilson   | Bellingen | Sales      |
 +-------------+---------------+-----------+------------+

mysql> DELETE FROM employees PARTITION (p0, p1) WHERE fname LIKE 'j%';
 Query OK, 2 rows affected (0.09 sec)

mysql> UPDATE employees PARTITION (p0) SET store_id = 2 WHERE fname = 'Jill';
 Query OK, 0 rows affected (0.00 sec) Rows matched: 0 Changed: 0 Warnings: 0

mysql> INSERT INTO employees PARTITION (p2) VALUES (20, 'Jan', 'Jones', 1, 3);
 ERROR 1729 (HY000): Found a row not matching the given partition set
 
mysql> INSERT INTO employees PARTITION (p3) VALUES (20, 'Jan', 'Jones', 1, 3);
 Query OK, 1 row affected (0.07 sec)

MySQL表分区函数

表分区函数可以使⽤的函数包含以下这些:


你可能感兴趣的:(十、MySQL表分区)