メインコンテンツまでスキップ
メインコンテンツまでスキップ

カスタムパーティショニングキー

注記

ほとんどの場合、パーティションキーは必要ありません。その他のほとんどの場合も、月単位よりも細かいパーティションキーは必要ありません。

過度に細かいパーティショニングは行わないでください。クライアントの識別子や名前でデータをパーティショニングしないでください。代わりに、クライアントの識別子や名前をORDER BY式の最初のカラムにしてください。

パーティショニングは、MergeTreeファミリーのテーブルレプリケーティッドテーブルマテリアライズドビューに利用できます。

パーティションは、指定された基準によるテーブル内のレコードの論理的な組み合わせです。パーティションは、月、日、イベントタイプなどの任意の基準で設定できます。各パーティションは、データの操作を簡略化するために別々に保存されます。データにアクセスする際、ClickHouseは可能な限り最小のパーティションのサブセットを使用します。パーティションは、パーティショニングキーを含むクエリのパフォーマンスを向上させます。なぜなら、ClickHouseはパーティション内の部分とグラニュールを選択する前に、そのパーティションのフィルタリングを行うからです。

パーティションは、テーブルを作成する際PARTITION BY expr句で指定されます。パーティションキーはテーブルのカラムからの任意の式であることができます。例えば、月ごとのパーティショニングを指定するには、次の式を使用します:toYYYYMM(date_column)

パーティションキーは、式のタプルでも構いません(主キーに似ています)。例えば:

この例では、現在の週に発生したイベントタイプによるパーティショニングを設定しています。

デフォルトでは、浮動小数点のパーティションキーはサポートされていません。使用するには、設定allow_floating_point_partition_keyを有効にします。

テーブルに新しいデータを挿入すると、このデータは主キーによってソートされた別のパート(チャンク)として保存されます。挿入後10~15分で、同じパーティションの部分がすべてのパートにマージされます。

参考

マージは、パーティショニング式の同じ値を持つデータ部分に対してのみ機能します。これはつまり、過度に細かいパーティション(約1000を超えるパーティション)は作成すべきではありません。そうでないと、ファイルシステム内のファイル数やオープンファイルディスクリプタの数が不合理に増えるため、SELECTクエリのパフォーマンスが悪化します。

テーブルのパーツやパーティションを表示するには、system.partsテーブルを使用します。例えば、月単位のパーティショニングを持つvisitsテーブルがあるとしましょう。system.partsテーブルに対してSELECTクエリを実行します:

partitionカラムにはパーティションの名前が含まれています。この例では2つのパーティション:201901201902があります。このカラムの値を使用して、ALTER ... PARTITIONクエリでパーティション名を指定できます。

nameカラムにはパーティションデータの名前が含まれています。このカラムを使用して、ALTER ATTACH PARTクエリでパートの名前を指定できます。

パートの名前『201901_1_9_2_11』を分解すると:

  • 201901はパーティション名です。
  • 1はデータブロックの最小番号です。
  • 9はデータブロックの最大番号です。
  • 2はチャンクレベル(マージツリーが形成された深さ)です。
  • 11は変異のバージョン(パートが変異した場合)
参考

古いタイプのテーブルのパーツは、名前が20190117_20190123_2_2_0の形式です(最小日-最大日-最小ブロック番号-最大ブロック番号-レベル)。

activeカラムはパートのステータスを表示します。1はアクティブ、0は非アクティブです。非アクティブなパーツは、例えば、より大きなパートにマージされた後のソースパーツです。破損したデータパーツも非アクティブとして示されます。

この例のように、同じパーティションに複数の分離されたパーツが存在します(例えば、201901_1_3_1201901_1_9_2)。これは、これらのパーツがまだマージされていないことを意味します。ClickHouseは、データの挿入後約15分で挿入されたパーツを定期的にマージします。加えて、OPTIMIZEクエリを使用して、非スケジュールのマージを実行することも可能です。例:

非アクティブなパーツは、マージ後約10分で削除されます。

パーツとパーティションのセットを表示するもう一つの方法は、テーブルのディレクトリに入ることです:/var/lib/clickhouse/data/<database>/<table>/。例えば:

201901_1_1_0201901_1_7_1などのフォルダは、パーツのディレクトリです。各パートは対応するパーティションに関連付けられており、特定の月のデータのみを含みます(この例のテーブルは月単位のパーティショニングです)。

detachedディレクトリには、DETACHクエリを使用してテーブルから切り離されたパーツが含まれています。破損したパーツも削除されるのではなく、このディレクトリに移動されます。サーバーはdetachedディレクトリ内のパーツを使用しません。このディレクトリ内でデータを追加、削除、または変更することはいつでも可能です – サーバーは、ATTACHクエリを実行するまではこれを把握しません。

運用中のサーバーでは、ファイルシステム上のパーツまたはそのデータのセットを手動で変更することはできません。サーバーはそのことを把握しなくなるためです。非レプリケートテーブルの場合、サーバーが停止しているときにこれを行うことができますが、推奨されません。レプリケートテーブルの場合、パーツのセットはどのような場合でも変更できません。

ClickHouseでは、パーティションに対して操作を行うことができます。削除、別のテーブルへのコピー、またはバックアップの作成などです。パーティションとパーツの操作に関するセクションに、すべての操作のリストがあります。

パーティションキーを使用したグループ化の最適化

テーブルのパーティションキーとクエリのグループバイキーの組み合わせによっては、各パーティションを独立して集約することが可能な場合があります。 その場合、最後にすべての実行スレッドの部分的に集約されたデータをマージする必要がなくなります。 なぜなら、各グループバイキーの値は、異なる2つのスレッドの作業セットに現れないという保証があるからです。

典型的な例:

注記

このようなクエリのパフォーマンスは、テーブルのレイアウトに大きく依存します。そのため、最適化はデフォルトでは無効になっています。

良好なパフォーマンスのための重要な要因:

  • クエリに関与するパーティションの数は十分大きく(max_threads / 2よりも多く)、そうでなければクエリはマシンを十分に活用しません
  • パーティションはあまり小さくないべきで、バッチ処理が1行ずつの処理に低下しないようにします
  • パーティションはサイズが比較可能であるべきで、したがってすべてのスレッドはほぼ同じ量の作業を行います
参考

データをパーティションに均等に分配するために、partition by句のカラムに対して何らかのハッシュ関数を適用することをお勧めします。

関連する設定は:

  • allow_aggregate_partitions_independently - 最適化の使用が有効かどうかを制御します
  • force_aggregate_partitions_independently - 正確さの観点から適用可能である場合にそれを強制使用しますが、内部ロジックがその妥当性を推定して無効にすることがあります
  • max_number_of_partitions_for_independent_aggregation - テーブルが持ち得るパーティションの最大数に対する厳密な制限です