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


24.2.1 RANGE パーティショニング

範囲によってパーティション化されるテーブルは、各パーティションに含まれる行のパーティショニング式値が指定された範囲に収まるようにパーティション化されます。 範囲は、連続しているけれども重複しないものであるべきで、VALUES LESS THAN 演算子を使用して定義されます。 次のいくつかの例では、20 のビデオ店で構成されるチェーン (1 から 20 までの番号が付けられている) の従業員レコードを保持する、次のようなテーブルを作成していると想定してください。

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 NOT NULL,
    store_id INT NOT NULL
);
注記

ここで使用する employees テーブルには主キーまたは一意キーがありません。 これらの例はここでの説明のためのもので、実際のテーブルは主キー、一意キー、またはその両方を備えている可能性がきわめて高く、パーティショニングカラムに利用できる選択肢はこれらのキー (ある場合) に使用されるカラムに依存します。 これらの事項については、セクション24.6.1「パーティショニングキー、主キー、および一意キー」を参照してください。

このテーブルは、必要に応じていくつかの方法で、範囲によるパーティション化を実行できます。 1 つの方法は、store_id カラムを使用することです。 たとえば、次のように PARTITION BY RANGE 句を追加することで、テーブルを 4 つのパーティションに分割することを決定できます。

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 NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN (21)
);

このパーティショニングスキームでは、店舗 1 から店舗 5 で働いている従業員に対応するすべての行がパーティション p0 に格納され、店舗 6 から店舗 10 の従業員がパーティション p1 に格納されます (以下同様)。 各パーティションは、最低から最高の順に定義されます。 これは PARTITION BY RANGE 構文の要件です。これは、C または Java の一連の if ... elseif ... ステートメントに似ていると考えることができます。

(72, 'Mitchell', 'Wilson', '1998-06-25', NULL, 13) データを含む新しい行がパーティション p2 に挿入されたことを簡単に判別できますが、チェーンで 21 の st ストアが追加されるとどうなりますか。 このスキームでは、store_id が 20 よりも大きい行に対応するルールがなく、サーバーはどこに置くべきかがわからないため、エラーになります。 これが発生しないようにするには、すべての状況に対応する VALUES LESS THAN 句を 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 NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

(この章のその他の例と同様に、デフォルトのストレージエンジンは InnoDB であると想定しています。)

注記

一致する値が見つからないときにエラーを回避するための別の方法は、INSERT ステートメントの一部として IGNORE キーワードを使用することです。 例については、セクション24.2.2「LIST パーティショニング」を参照してください。 また、IGNORE の一般的な情報については、セクション13.2.6「INSERT ステートメント」を参照してください。

MAXVALUE は、可能な最大整数値よりも確実に大きな整数値を表します (数学用語では、上限です)。 これによって、store_id カラム値が 16 (定義されている最大値) 以上である行は、パーティション p3 に格納されます。 将来のある時点で、店舗の数が 25、30、またはそれ以上に増加したときは、ALTER TABLE ステートメントを使用して、店舗 21-25、26-30 などのための新しいパーティションを追加できます (これを行う方法の詳細については、セクション24.3「パーティション管理」を参照してください)。

同様に、従業員ジョブコードに基づいて (つまり、job_code カラム値の範囲に基づいて) テーブルをパーティション化できます。 たとえば、正規 (インストア) 従業員に 2 桁のジョブコード、オフィスおよびサポート従業員に 3 桁のコード、および管理職に 4 桁のコードが使用されると想定すると、次のステートメントを使用してパーティション化されたテーブルを作成できます。

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 NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (job_code) (
    PARTITION p0 VALUES LESS THAN (100),
    PARTITION p1 VALUES LESS THAN (1000),
    PARTITION p2 VALUES LESS THAN (10000)
);

この例では、インストア従業員に関連するすべての行はパーティション p0、オフィスおよびサポートスタッフに関連するものは p1、および管理職に関連するものはパーティション p2 に格納されます。

VALUES LESS THAN 句に式を使用することもできます。 ただし、MySQL は、LESS THAN (<) 比較の一環として式の戻り値を評価できる必要があります。

店舗番号に従ってテーブルデータを分割するのではなく、代わりに 2 つの DATE カラムのうちの 1 つに基づく式を使用できます。 たとえば、各従業員が会社を退職した年 (つまり、YEAR(separated) の値) に基づいてパーティション化するとします。 そのようなパーティショニングスキームを実装する 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 RANGE ( YEAR(separated) ) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1996),
    PARTITION p2 VALUES LESS THAN (2001),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

このスキームでは、1991 年より前に退職したすべての従業員の場合、行はパーティション p0 に格納されます。1991 年から 1995 年までに退職した人は p1、1996 年から 2000 年までに退職した人は p2、および 2000 年よりあとに退職した従業員は p3 に格納されます。

次の例に示すように、UNIX_TIMESTAMP() 関数を使用して、TIMESTAMP カラムの値に基づいて、RANGE によってテーブルをパーティション化することもできます。

CREATE TABLE quarterly_report_status (
    report_id INT NOT NULL,
    report_status VARCHAR(20) NOT NULL,
    report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
    PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
    PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
    PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
    PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
    PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
    PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
    PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
    PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
    PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
    PARTITION p9 VALUES LESS THAN (MAXVALUE)
);

TIMESTAMP 値を含むほかの式は許可されません (Bug #42849 を参照してください)。

次の条件の 1 つ以上が true のときは、RANGE パーティショニングが特に役立ちます。

  • 古いデータを削除したい、またはする必要がある。 前述の employees テーブルのパーティション化スキームを使用している場合は、ALTER TABLE employees DROP PARTITION p0;を使用して、1991 年より前に企業の勤務を停止した従業員に関連するすべての行を削除できます。 (詳細は、セクション13.1.9「ALTER TABLE ステートメント」およびセクション24.3「パーティション管理」を参照してください)。 テーブルに多数の行がある場合、これは DELETE FROM employees WHERE YEAR(separated) <= 1990; などの DELETE クエリーを実行するよりもはるかに効率的な場合があります。

  • 日付または時間値、または何らかのほかの一連値から生じる値が含まれるカラムを使用したい。

  • テーブルのパーティショニングに使用されるカラムに直接依存するクエリーを頻繁に実行する。 たとえば、EXPLAIN SELECT COUNT(*) FROM employees WHERE separated BETWEEN '2000-01-01' AND '2000-12-31' GROUP BY store_id;などのクエリーを実行する場合、MySQL では、WHERE 句を満たすレコードを残りのパーティションに含めることができないため、パーティション p2 のみをスキャンする必要があると迅速に判断できます。 これがどのように実現されるかについての詳細は、セクション24.4「パーティションプルーニング」を参照してください。

このタイプのパーティショニングのバリアントが RANGE COLUMNS パーティショニングです。 RANGE COLUMNS によるパーティショニングでは、複数のカラムを使用してパーティショニング範囲を定義できます (パーティション内での行の配置、およびパーティションプルーニングを実行するときに特定のパーティションの包含または除外を判断する際に適用されます)。 詳細は、セクション24.2.3.1「RANGE COLUMNS パーティショニング」を参照してください。

時間間隔に基づくパーティショニングスキーム.  MySQL 8.0 で時間の範囲または間隔に基づいてパーティショニングスキームを実装する場合は、2 つの方法があります。

  1. 次のように、RANGE によってテーブルをパーティション化し、パーティショニング式に DATETIME、または DATETIME カラムを操作して整数値を返す関数を使用します。

    CREATE TABLE members (
        firstname VARCHAR(25) NOT NULL,
        lastname VARCHAR(25) NOT NULL,
        username VARCHAR(16) NOT NULL,
        email VARCHAR(35),
        joined DATE NOT NULL
    )
    PARTITION BY RANGE( YEAR(joined) ) (
        PARTITION p0 VALUES LESS THAN (1960),
        PARTITION p1 VALUES LESS THAN (1970),
        PARTITION p2 VALUES LESS THAN (1980),
        PARTITION p3 VALUES LESS THAN (1990),
        PARTITION p4 VALUES LESS THAN MAXVALUE
    );

    MySQL 8.0 では、次の例に示すように UNIX_TIMESTAMP() 関数を使用して、TIMESTAMP カラムの値に基づいて RANGE によってテーブルをパーティション化することもできます。

    CREATE TABLE quarterly_report_status (
        report_id INT NOT NULL,
        report_status VARCHAR(20) NOT NULL,
        report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    )
    PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
        PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
        PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
        PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
        PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
        PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
        PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
        PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
        PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
        PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
        PARTITION p9 VALUES LESS THAN (MAXVALUE)
    );

    MySQL 8.0 では、TIMESTAMP 値を含むほかの式は許可されません。 (Bug #42849 を参照してください)。

    注記

    MySQL 8.0 では、LIST によってパーティション化されるテーブルのパーティショニング式として UNIX_TIMESTAMP(timestamp_column) を使用することもできます。 ただし、このようにするのは通常は実用的ではありません。

  2. DATE または DATETIME カラムをパーティショニングカラムとして使用して、RANGE COLUMNS によってテーブルをパーティション化します。 たとえば、次のように joined カラムを直接使用して members テーブルを定義できます。

    CREATE TABLE members (
        firstname VARCHAR(25) NOT NULL,
        lastname VARCHAR(25) NOT NULL,
        username VARCHAR(16) NOT NULL,
        email VARCHAR(35),
        joined DATE NOT NULL
    )
    PARTITION BY RANGE COLUMNS(joined) (
        PARTITION p0 VALUES LESS THAN ('1960-01-01'),
        PARTITION p1 VALUES LESS THAN ('1970-01-01'),
        PARTITION p2 VALUES LESS THAN ('1980-01-01'),
        PARTITION p3 VALUES LESS THAN ('1990-01-01'),
        PARTITION p4 VALUES LESS THAN MAXVALUE
    );
注記

DATE または DATETIME 以外の日付または時間型を使用してパーティショニングカラムを使用することは、RANGE COLUMNS ではサポートされません。


関連キーワード:  PARTITION, LESS, THAN, VALUES, NOT, TIMESTAMP, パーティショニング, RANGE, テーブル, VARCHAR