MySQL 中的列表分区与范围分区类似,都是明确定义每个分区。两种分区类型的主要区别在于,列表分区是根据某一列值是否在某个值列表中来选择分区的,而不是根据某个连续的值范围。可以使用 PARTITION BY LIST(
,其中 expr
)expr
是一个列值或基于列值的表达式,返回整数值,然后使用 VALUES IN (
定义每个分区,其中 value_list
)value_list
是一个逗号分隔的整数列表。
在 MySQL 8.3 中,可以在列表分区中匹配整数列表(可能还有 NULL
,见 第 26.2.7 节,“MySQL 分区处理 NULL”)。
然而,在使用 LIST COLUMN
分区时,可以在值列表中使用其他列类型,这将在本节后面描述。
与范围分区不同,列表分区不需要按照特定的顺序声明。有关语法信息,请参阅 第 15.1.20 节,“CREATE TABLE 语句”。
以下示例假设要分区的表的基本定义由 CREATE TABLE
语句提供:
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
);
(这与范围分区示例中使用的表相同。我们假设 default_storage_engine
是 InnoDB
。)
假设有 20 家视频店分布在 4 个特许经营权中,如下表所示。
Region | Store ID Numbers |
---|---|
北方 | 3, 5, 6, 9, 17 |
东方 | 1, 2, 10, 11, 19, 20 |
西方 | 4, 12, 13, 14, 18 |
中部 | 7, 8, 15, 16 |
要将该表分区,使得同一地区的店铺记录存储在同一个分区中,可以使用以下 CREATE TABLE
语句:
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)
);
这样可以轻松地添加或删除特定地区的员工记录。例如,如果西方地区的所有店铺被卖给另一家公司,在 MySQL 8.3 中,可以使用 ALTER TABLE employees TRUNCATE PARTITION pWest
语句删除所有西方地区的员工记录,这比等效的 DELETE
语句 DELETE FROM employees WHERE store_id IN (4,12,13,14,18);
更高效。(使用 ALTER TABLE employees DROP PARTITION pWest
也可以删除所有这些记录,但也将从表定义中删除分区 pWest
;需要使用 ALTER TABLE ... ADD PARTITION
语句来恢复表的原始分区方案。)
与范围分区一样,也可以将列表分区与哈希或键分区结合使用,以生成复合分区(子分区)。见 第 26.2.6 节,“子分区”。
与范围分区不同,列表分区没有类似 MAXVALUE
的“catch-all”;所有预期的分区表达式值都应该在 PARTITION ... VALUES IN (...)
子句中涵盖。如果 INSERT
语句包含未匹配的分区列值,将出现错误,如示例所示:
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)
mysql> INSERT INTO h2 VALUES (3, 5);
ERROR 1525 (HY000): Table has no partition for value 3
使用单个 INSERT
语句将多行插入到单个 InnoDB
表中时,InnoDB
将该语句视为单个事务,因此如果存在任何不匹配的值,语句将完全失败,不插入任何行。
您可以使用 IGNORE
关键字忽略这种类型的错误,尽管对于每行包含不匹配的分区列值的警告,如下所示。
mysql> TRUNCATE h2;
Query OK, 1 row affected (0.00 sec)
mysql> TABLE h2;
Empty set (0.00 sec)
mysql> INSERT IGNORE INTO h2 VALUES (2, 5), (6, 10), (7, 5), (3, 1), (1, 9);
Query OK, 3 rows affected, 2 warnings (0.01 sec)
Records: 5 Duplicates: 2 Warnings: 2
mysql> SHOW WARNINGS;
+---------+------+------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------+
| Warning | 1526 | Table has no partition for value 6 |
| Warning | 1526 | Table has no partition for value 3 |
+---------+------+------------------------------------+
2 rows in set (0.00 sec)
您可以在以下 TABLE
语句的输出中看到,包含不匹配分区列值的行被默默拒绝,而不包含不匹配值的行被插入到表中:
mysql> TABLE h2;
+------+------+
| c1 | c2 |
+------+------+
| 7 | 5 |
| 1 | 9 |
| 2 | 5 |
+------+------+
3 rows in set (0.00 sec)
MySQL 还提供了对 LIST COLUMNS
分区的支持,这是一种变体的 LIST
分区,启用您使用非整数类型的列作为分区列,并使用多个列作为分区键。有关更多信息,请参阅 第 26.2.3.2 节,“LIST COLUMNS 分区”。