MySQL 中的清單分割區在許多方面與範圍分割區相似。如同依 RANGE
分割區一樣,每個分割區都必須明確定義。兩種分割區類型之間的主要差異在於,在清單分割區中,每個分割區都是根據欄位值是否屬於值清單集合之一來定義和選取,而不是屬於值的連續範圍集合之一。這是透過使用 PARTITION BY LIST(
來完成的,其中 expr
)expr
是一個欄位值或基於欄位值的運算式,並傳回一個整數值,然後透過 VALUES IN (
來定義每個分割區,其中 value_list
)value_list
是以逗號分隔的整數清單。
在 MySQL 9.0 中,當依 LIST
分割區時,只能比對整數清單(並且可能包含 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
);
(這與 第 26.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 9.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
分割區與雜湊或金鑰分割區結合,以產生複合分割區(子分割區)。請參閱 第 26.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> 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 分割區」。