パーティションキーの選定方法
パーティショニングは主にデータ管理のための手法であり、クエリ最適化ツールではありません。特定のワークロードではパフォーマンスを向上させることもありますが、クエリを高速化するために最初に用いるべき仕組みではありません。パーティショニングキーは、その影響を明確に理解したうえで慎重に選択する必要があり、データライフサイクルの要件や十分に理解されたアクセスパターンに合致する場合にのみ適用すべきです。
ClickHouse においてパーティショニングは、指定されたキーに基づいてデータを論理的なセグメントに整理する仕組みです。これはテーブル作成時に PARTITION BY 句を用いて定義され、時間間隔、カテゴリ、その他のビジネス上重要なディメンションごとに行をグループ化するためによく使用されます。パーティショニング式の各一意の値はディスク上で独立した物理パーティションを形成し、ClickHouse はそれぞれの値ごとにデータを別々のパートに保存します。パーティショニングによりデータ管理が改善され、データ保持ポリシーが簡素化され、特定のクエリパターンにおいては役立つことがあります。
たとえば、パーティショニングキー toStartOfMonth(date) を使用する、以下の UK price paid データセットのテーブルを考えてみましょう。
テーブルに一連の行が挿入されると、挿入されたすべての行を含む 1 つのデータパーツ(少なくとも 1 つ)(こちらで説明)を作成するのではなく、ClickHouse は挿入された行に含まれる一意なパーティションキー値ごとに 1 つの新しいデータパーツを作成します。

ClickHouse サーバーは、上の図で示した 4 行を持つサンプルの INSERT 文で挿入された行を、パーティションキー値 toStartOfMonth(date) ごとにまず分割します。次に、特定された各パーティションについて、行を ① ソート、② 列への分割、③ 圧縮、④ ディスクへの書き込み、といういくつかの順次ステップを実行して通常どおり処理します。
パーティション分割の詳細な説明については、このガイドを参照することをお勧めします。
パーティション分割が有効になっている場合、ClickHouse はパーティション内でのみデータパーツをマージし、パーティションをまたいではマージしません。上のサンプルテーブルを用いてこれを図示します。

パーティショニングの用途
パーティショニングは、特にオブザーバビリティおよび分析系のユースケースにおいて、ClickHouse で大規模データセットを管理するための強力な手法です。パーティション単位(多くの場合、時間やビジネスロジックに沿って定義される)で削除・移動・アーカイブといったデータライフサイクル処理を単一のメタデータ操作として実行できるため、高効率な運用が可能になります。これは、行単位の削除やコピー操作と比べて、はるかに高速かつリソース消費も少なくなります。さらにパーティショニングは、TTL や階層型ストレージといった ClickHouse の機能とシームレスに統合されるため、カスタムのオーケストレーションを行わなくても、保持ポリシーやホット/コールドストレージ戦略を実装できます。たとえば、直近のデータは高速な SSD バックエンドストレージ上に保持し、古いパーティションは自動的により安価なオブジェクトストレージへ移動するといった構成が可能です。
パーティショニングは、ワークロードによってはクエリパフォーマンスを改善する一方で、応答時間に悪影響を与える可能性もあります。
パーティションキーがプライマリキーに含まれておらず、そのキーでフィルタリングしている場合、パーティショニングによってクエリパフォーマンスの改善が見込めることがあります。例についてはこちらを参照してください。
逆に、クエリが複数のパーティションにまたがってアクセスする必要がある場合、パーツの総数が増えることでパフォーマンスが低下する可能性があります。このため、パーティショニングをクエリ最適化手法として検討する前に、自分たちのアクセスパターンを十分に理解しておく必要があります。
まとめると、ユーザーはパーティショニングを主にデータ管理のテクニックとして捉えるべきです。データ管理の具体例については、オブザーバビリティユースケースガイドの「Managing Data」および Core Concepts - Table partitions の「What are table partitions used for?」を参照してください。
低カーディナリティなパーティショニングキーを選択する
重要なのは、パーツ数が多いほどクエリ性能に悪影響を及ぼすという点です。そのため、パーツ数が指定された制限を超えた場合、ClickHouse は “too many parts” エラーを INSERT に対して返します。この制限は全体またはパーティション単位のいずれかで定義されます。
パーティショニングキーのカーディナリティを適切に選択することは非常に重要です。異なるパーティション値の数が多い高カーディナリティなパーティショニングキーは、多数のデータパーツの生成を招きます。ClickHouse はパーティションをまたいだパーツのマージを行わないため、パーティションが多すぎるとマージされないパーツが過剰に増加し、最終的には “Too many parts” エラーを引き起こします。マージは ストレージの断片化を低減し、クエリ速度を最適化するために不可欠ですが、高カーディナリティなパーティションではそのマージのポテンシャルが十分に発揮されません。
これに対して、低カーディナリティなパーティショニングキー(異なる値が 100 ~ 1,000 未満程度)が通常は最適です。これによりパーツのマージが効率的に行え、メタデータのオーバーヘッドを抑え、ストレージにおける過剰なオブジェクト作成も回避できます。加えて、ClickHouse はパーティション列に対して自動的に MinMax インデックスを構築するため、それらの列でフィルタするクエリを大幅に高速化できます。たとえば、テーブルが toStartOfMonth(date) でパーティション分割されている場合に月単位でフィルタすると、エンジンは無関係なパーティションおよびそのパーツをまるごとスキップできます。
パーティショニングは一部のクエリパターンでは性能を向上させますが、主にデータ管理のための機能です。多くの場合、データの断片化が増え、スキャン対象のパーツ数も多くなるため、すべてのパーティションをまたいでクエリを行うと、非パーティションテーブルより遅くなることがあります。パーティショニングは慎重に使用し、選択するキーは常に低カーディナリティであり、データライフサイクルポリシー(例: TTL による保持期間)と整合していることを確認してください。パーティショニングが本当に必要か判断できない場合は、まずはパーティショニングなしで開始し、実際のアクセスパターンを観察したうえで後から最適化する方法も検討できます。