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


24.2.4 HASH パーティショニング

HASH によるパーティショニングは、事前に決められた数のパーティションにデータを均等に配分するために主に使用されます。 レンジパーティション化またはリストパーティション化では、特定のカラム値またはカラム値のセットを格納するパーティションを明示的に指定する必要があります。ハッシュパーティション化では、この決定が行われ、ハッシュされるカラム値およびパーティションテーブルが分割されるパーティションの数に基づいてカラム値または式のみを指定する必要があります。

HASH パーティショニングを使用してテーブルをパーティション化する場合は、CREATE TABLE ステートメントに PARTITION BY HASH (expr) 句を付加する必要があります。ここで、expr は整数を返す式です。 これは、型が MySQL 整数型のいずれかであるカラムの名前にすることができます。 また、多くの場合、この後に PARTITIONS num を使用します。ここで、num は、テーブルが分割されるパーティションの数を表す正の整数です。

注記

わかりやすくするため、次の例のテーブルではキーを使用していません。 テーブルに一意キーがある場合、このテーブルのパーティション化式で使用されるすべてのカラムは、主キーを含むすべての一意キーの一部である必要があります。 詳しくはセクション24.6.1「パーティショニングキー、主キー、および一意キー」,をご覧ください。

次のステートメントは、store_id カラムにハッシュを使用し、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,
    store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4;

PARTITIONS 句を含めない場合、パーティションの数はデフォルトで 1 になります。PARTITIONS キーワードを数字なしで使用すると、構文エラーが発生します。

整数を返す SQL 式を expr に使用することもできます。 たとえば、従業員が雇用された年度に基づいてパーティション化するとします。 これは、次のように行うことができます。

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 HASH( YEAR(hired) )
PARTITIONS 4;

expr は、定数以外のランダムではない整数値 (つまり、変化するけれども決定論的であるべき) を返す必要があり、セクション24.6「パーティショニングの制約と制限」で説明されている禁止された構造体を含んでいてはいけません。 また、この式は行が挿入または更新 (または場合によっては削除) されるたびに評価されるべきです。これは、非常に複雑な式がパフォーマンスの問題を起こすことがあることを意味します (特に、一度に多くの行に影響する操作 (バッチ挿入など) を実行するとき)。

もっとも効率的なハッシュ関数は、単一テーブルカラムに実行され、その値がカラム値に対して比例的に増加または減少するもので、これによってパーティションの範囲をプルーニングできます。 つまり、式がそのベースのカラムの値に対してより密接に変化するほど、MySQL は式を HASH パーティショニングにより効率的に使用できます。

たとえば、date_colDATE 型のカラムである場合、式 TO_DAYS(date_col)date_col の値に正比例すると表現されます。date_col の値が変わるたびに、式の値が一定の方法で変化するためです。 date_col に対する式 YEAR(date_col) の変化は、TO_DAYS(date_col) ほど比例的ではありません。date_col のあらゆる変化に対して YEAR(date_col) が同等に変化するとはかぎらないためです。 それでも、YEAR(date_col) はハッシュ関数の良い候補の 1 つです。date_col の一部と正比例し、date_col の変化によって YEAR(date_col) で比例的でない変化が発生することがないためです。

比較のために、型が INT である int_col という名前のカラムがあるとします。 式 POW(5-int_col,3) + 6 を検討してみてください。 これは、int_col の値が変化したときに、式の値に比例的に変化することが保証されないため、ハッシュ関数の良い候選択肢ではありません。 int_col の値を特定の量で変更すると、式の値に大きく異なる変更が生じる可能性があります。 たとえば、int_col5 から 6 に変化すると、式の値が -1 に変化しますが、int_col の値が 6 から 7 に変化すると、式の値が -7 に変化します。

つまり、カラム値と式の値のグラフが、等式 y=cx (ここで、c はゼロでない何らかの定数) によって描かれるような直線に近くなるほど、その式はハッシュにより適切になります。 これは、式が非直線的であるほど、パーティションに対するデータの配分が不均衡になる傾向があることに関係しています。

理論上は、複数のカラム値を使用する式をプルーニングすることもできますが、そのような式のどれが適しているかを判断するのがかなり難しく、時間がかかることがあります。 このため、複数のカラムを含むハッシュ式を使用することはあまり推奨されていません。

PARTITION BY HASH を使用する場合、ストレージエンジンは式の結果のモジュラスに基づいて、使用する num パーティションのパーティションを決定します。 つまり、特定の式 expr の場合、レコードが格納されるパーティションはパーティション番号 N で、 N = MOD( expr, num) です。 テーブル t1 が次のように 4 つのパーティションを持つように定義されているとします。

CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY HASH( YEAR(col3) )
    PARTITIONS 4;

t1col3 値が '2005-09-15' であるレコードを挿入した場合、それが格納されるパーティションは次のように判断されます。

MOD(YEAR('2005-09-01'),4)
=  MOD(2005,4)
=  1

MySQL 8.0 では、線形ハッシングと呼ばれる HASH パーティション化のバリアントもサポートされており、パーティションテーブルに挿入される新しい行の配置を決定するためのより複雑なアルゴリズムが採用されています。 このアルゴリズムについては、セクション24.2.4.1「LINEAR HASH パーティショニング」を参照してください。

ユーザー指定の式は、レコードが挿入または更新されるたびに評価されます。 状況によっては、レコードが削除されるときにも評価されることがあります。


関連キーワード:  col, パーティショニング, HASH, カラム, 変化, date, テーブル, INT, YEAR, expr