MySQL 8.4 參考手冊  /  ...  /  LIST 分割

26.2.2 LIST 分割

MySQL 中的清單分割在許多方面與範圍分割相似。如同透過 RANGE 分割一樣,每個分割區都必須明確定義。這兩種分割類型之間的主要差異在於,在清單分割中,每個分割區的定義和選擇是基於欄位值是否屬於一組值清單,而不是屬於一組連續的值範圍。這是透過使用 PARTITION BY LIST(expr) 來完成,其中 expr 是欄位值或基於欄位值並傳回整數值的表達式,然後透過 VALUES IN (value_list) 來定義每個分割區,其中 value_list 是以逗號分隔的整數清單。

注意

在 MySQL 8.4 中,當使用 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 8.4 中,可以使用查詢 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 分割〉