MySQL 9.0 參考手冊  /  ...  /  LIST 分割區

26.2.2 LIST 分割區

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_engineInnoDB。)

假設有 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 分割區」