MySQL 8.0 リファレンスマニュアル


24.2.2 LIST パーティショニング

MySQL の LIST パーティショニングは、多くの点で RANGE パーティショニングに似ています。 RANGE によるパーティショニングと同様に、各パーティションを明示的に定義する必要があります。 2 つのタイプのパーティショニングの主な違いは、LIST パーティショニングでは、各パーティションが、連続する値の範囲のセットのいずれかではなく、値リストのセットのいずれかに含まれるカラム値のメンバーシップに基づいて定義および選択されることです。 これを行うには、PARTITION BY LIST (expr) を使用します。ここで、expr はカラム値またはカラム値に基づく式で、整数値を返し、VALUES IN (value_list) で各パーティションを定義します。ここで、value_list はカンマで区切られた整数のリストです。

注記

MySQL 8.0 では、LIST によってパーティション化するときに、整数 (および NULL も可。セクション24.2.7「MySQL パーティショニングによる NULL の扱い」を参照してください) のリストに対してのみ照合できます。

ただし、LIST COLUMN パーティショニングを使用するときは、ほかのカラムタイプを値リストで使用できます (これについては、このセクションで後述します)。

範囲で定義されるパーティションの場合と異なり、リストパーティションは特定の順序で宣言する必要はありません。 構文についての詳細は、セクション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_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.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 パーティショニング」を参照してください。


関連キーワード:  パーティショニング, LIST, PARTITION, ステートメント, VALUES, テーブル, IN, TABLE, RANGE, INT