MySQL 中的列表分区在许多方面类似于范围分区。与按 分区一样RANGE
,每个分区都必须明确定义。两种类型的分区之间的主要区别在于,在列表分区中,每个分区的定义和选择基于列值在一组值列表之一中的成员资格,而不是在一组连续范围之一中的成员资格。值。这是通过使用where
是列值或基于列值并返回整数值的表达式,然后通过 定义每个分区来完成的
,where
是逗号分隔的整数列表。
PARTITION BY
LIST(
expr
)expr
VALUES IN
(
value_list
)value_list
与按范围定义分区的情况不同,列表分区不需要以任何特定顺序声明。有关更详细的语法信息,请参阅 第 13.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
);
(这是用作第 24.2.1 节“RANGE 分区”
中示例基础的同一张表
。与其他分区示例一样,我们假设
default_storage_engine
是
InnoDB
。)
假设有 20 家音像店分布在 4 个特许经营店中,如下表所示。
地区 | 商店 ID 号 |
---|---|
北 | 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.0 中,所有与该地区门店工作的员工相关的行都可以通过查询删除
,这比等效
语句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
与RANGE
分区一样,可以将LIST
分区与按散列或键的分区相结合以产生复合分区(子分区)。请参阅
第 24.2.6 节,“子分区”。
与RANGE
分区的情况不同,没有“包罗万象”,例如
MAXVALUE
;分区表达式的所有预期值都应包含在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> SELECT * FROM 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 (0.00 sec)
Records: 5 Duplicates: 2 Warnings: 0
mysql> SELECT * FROM h2;
+------+------+
| c1 | c2 |
+------+------+
| 7 | 5 |
| 1 | 9 |
| 2 | 5 |
+------+------+
3 rows in set (0.00 sec)
MySQL 8.0 还提供了对分区的支持,LIST
COLUMNS
分区的一种变体
LIST
可以让你使用整数类型以外的类型的列来分区列,并使用多个列作为分区键。有关详细信息,请参阅
第 24.2.3.2 节,“LIST COLUMNS 分区”。