プロジェクションの概要
プロジェクションは、クエリ実行を最適化するフォーマットでデータを格納します。この機能は、次のような場合に役立ちます。- 主キーに含まれないカラムに対してクエリを実行する
- カラムを事前集計し、計算量と IO の両方を削減する
ディスク使用量プロジェクションは内部的に新しい非表示テーブルを作成するため、より多くの IO とディスク容量が必要になります。
たとえば、プロジェクションで異なる主キーを定義した場合、元のテーブルのすべてのデータが複製されます。
プロジェクションを使う
主キーを使わないフィルタリングの例
テーブルを作成します。ALTER TABLE を使用すると、既存のテーブルにプロジェクションを追加できます。
user_name が PRIMARY_KEY として定義されていなくても、user_name で高速に絞り込めます。
クエリ時には、データが user_name 順に並んでいるため、プロジェクションを使ったほうが処理されるデータ量が少なくなると ClickHouse が判断します。
system.query_log テーブルを確認します。projections フィールドには、使用されたプロジェクション名が入り、何も使用されていない場合は空です。
事前集計クエリの例
プロジェクションprojection_visits_by_user を持つテーブルを作成します:
user_agent を使って、GROUP BY を含む最初のクエリを実行します。
このクエリでは、事前集計が一致しないため、定義したプロジェクションは使用されません。
GROUP BY のフィールドの一部またはすべてを選択するクエリを実行できます。
system.query_log テーブルを確認することで把握できます。
projections フィールドには、使用されたプロジェクションの名前が表示されます。
プロジェクションが使用されていない場合、このフィールドは空になります。
プロジェクション索引の作成と使用
プロジェクション索引を作成するには、次のようにします。_part_offset フィールドは、マージやミューテーションを経てもその値が保持されるため、セカンダリ索引で有用です。これはクエリで活用できます:
WHERE 句付きPROJECTIONの例
PROJECTIONには WHERE 句を含めて、行の一部だけを格納できます。これは、クエリで特定の述語による絞り込みが頻繁に行われる場合に便利です。PROJECTIONは条件に一致する行だけを実体化するため、ストレージ使用量を削減し、クエリパフォーマンスを向上させます。
テーブルを作成し、フィルタ付きのPROJECTIONを追加します。
WHERE 句 がPROJECTIONの WHERE 句 を含意する場合 (つまり、PROJECTIONのフィルター内のすべての条件がクエリのフィルターにも含まれている場合) 、オプティマイザは、それが有益だと判断すると、そのPROJECTIONを自動的に使用できます。
プロジェクションの操作
プロジェクションに対しては、次の操作を実行できます:ADD PROJECTION
テーブルのメタデータにPROJECTIONの説明を追加するには、以下のステートメントを使用します。PROJECTIONで
WHERE 句を定義すると、述語条件に一致する行のみがマテリアライズされます。オプティマイザは、クエリの WHERE が論理的にPROJECTIONの WHERE を含意しており、かつそのPROJECTIONがクエリプランに有利である場合、そのようなPROJECTIONを利用できます。これは通常のPROJECTIONと集約PROJECTIONの両方に当てはまります。WITH SETTINGS 句
WITH SETTINGS ではプロジェクションレベルの設定を定義し、プロジェクションでのデータの格納方法 (たとえば index_granularity や index_granularity_bytes) をカスタマイズできます。
これらは MergeTree のテーブル設定 に直接対応していますが、適用されるのはこのプロジェクションのみです。
例:
MODIFY PROJECTION
以下のステートメントを使用すると、既存のPROJECTIONのデータを再構築せずに、WITH SETTINGS 句を変更できます。
SELECT クエリではなく INDEX 宣言を再度指定します:
WITH SETTINGS 句のみです。
既存のPROJECTIONパーツにはこの定義に基づいて構築されたデータが格納されているため、PROJECTIONのクエリ自体 (PROJECTION索引の場合は索引式と型) は変更できません。変更するには、DROP PROJECTION の後に ADD PROJECTION を使用します。
このコマンドはテーブルのメタデータのみを変更し、データの書き換えは行いません。既存のPROJECTIONパーツは書き込まれた時点の設定を保持し、以降の挿入およびマージで書き込まれるPROJECTIONパーツには新しい設定が使用されます。
MATERIALIZE PROJECTION を実行しても、既存のパーツに新しい設定は適用されません。このコマンドは、PROJECTIONが存在しないパーツや破損しているパーツに対してのみPROJECTIONを構築し、既存のPROJECTIONパーツには手を加えません。
新しい設定で既存のパーツを再構築するには、CLEAR PROJECTION の後に MATERIALIZE PROJECTION を実行するか、OPTIMIZE TABLE ... FINAL などでパーツをマージします。
例:
DROP PROJECTION
以下のステートメントを使用して、テーブルのメタデータからPROJECTIONの定義を削除し、ディスク上のPROJECTIONファイルを削除します。 これは ミューテーション として実装されています。MATERIALIZE PROJECTION
以下のステートメントを使用して、PROJECTIONname が存在しないパーツ、または破損しているパーツでPROJECTIONをビルドします。必要に応じて、対象をパーティション partition_name のみに限定することもできます。
すでにPROJECTIONを持つパーツは、書き込み後に MODIFY PROJECTION でPROJECTIONの設定が変更された場合でも、変更されません。これらのパーツを再構築するには、先に CLEAR PROJECTION を実行してください。
これは ミューテーション として実装されています。
CLEAR PROJECTION
説明を削除せずにディスク上のPROJECTIONファイルを削除するには、以下のステートメントを使用します。 これは ミューテーション として実装されています。ADD、MODIFY、DROP、CLEAR コマンドは、メタデータの変更またはファイルの削除だけを行うという意味で軽量です。
また、これらのコマンドはレプリケーションされ、ClickHouse Keeper または ZooKeeper を介してPROJECTIONのメタデータを同期します。
PROJECTIONの操作は、
*MergeTree エンジンのテーブルでのみサポートされます (レプリケーション対応のバリアントを含む) 。プロジェクションのマージ動作を制御する
クエリを実行すると、ClickHouse は元のテーブルまたはそのプロジェクションのいずれから読み取るかを選択します。 元のテーブルとそのプロジェクションのどちらから読み取るかの判断は、各テーブルパーツごとに個別に行われます。 ClickHouse は一般に、できるだけ少ないデータを読み取ることを目指しており、たとえばパーツの主キーをサンプリングするなど、最適な読み取り元のパーツを特定するためにいくつかの手法を用います。 場合によっては、元のテーブルのパーツに対応するプロジェクションパーツが存在しないことがあります。 これは、たとえば SQL でテーブルにプロジェクションを作成する処理がデフォルトで「遅延的」だからです。つまり、新たに挿入されるデータにのみ影響し、既存のパーツは変更されません。 いずれかのプロジェクションには事前計算済みの集約値がすでに含まれているため、ClickHouse はクエリ実行時に再度集約を行うことを避けるために、対応するプロジェクションパーツから読み取ろうとします。特定のパーツに対応するプロジェクションパーツがない場合、クエリ実行は元のパーツにフォールバックします。 しかし、元のテーブル内の行が、単純ではない data パーツ のバックグラウンドマージによって大きく変化した場合はどうなるでしょうか。 たとえば、そのテーブルがReplacingMergeTree テーブルエンジンを使用して保存されているとします。
マージ中に同じ行が複数の入力パーツで検出された場合、もっとも新しい行バージョン (もっとも最近に挿入されたパーツのもの) だけが保持され、それ以前のすべてのバージョンは破棄されます。
同様に、テーブルが AggregatingMergeTree テーブルエンジンを使用して保存されている場合、マージ操作によって、入力パーツ内の同じ行が主キーの値に基づいて 1 行にまとめられ、部分的な集約状態が更新されることがあります。
ClickHouse v24.8 より前では、プロジェクションパーツはメインデータと気づかれないまま同期がずれるか、あるいは更新や削除などの特定の操作をまったく実行できませんでした。これは、テーブルにプロジェクションがある場合、データベースが自動的に例外を送出していたためです。
v24.8 以降では、新しいテーブルレベル設定 deduplicate_merge_projection_mode により、前述の単純ではないバックグラウンドマージ操作が元のテーブルのパーツで発生した場合の動作を制御できます。
Delete mutations も、元のテーブルのパーツ内の行を削除する パーツ merge 操作の別の例です。v24.7 以降では、論理削除によってトリガーされる delete mutations に関する動作を制御する設定もあります: lightweight_mutation_projection_mode。
以下は、deduplicate_merge_projection_mode と lightweight_mutation_projection_mode の両方で設定可能な値です。
throw(デフォルト): 例外が送出され、プロジェクションパーツの同期ずれを防ぎます。drop: 影響を受けるプロジェクションテーブルパーツは削除されます。影響を受けたプロジェクションパーツについては、クエリは元のテーブルパーツにフォールバックします。rebuild: 影響を受けたプロジェクションパーツは、元のテーブルパーツ内のデータとの整合性を保つために再構築されます。
制限事項
プロジェクションのORDER BY句では、ALIASカラムは使用できません。例:
ALIAS カラムは物理的に保存されず、クエリ時にその場で計算されるため、ソート式が評価されるプロジェクションパートの書き込み処理では使用できません。
代わりに、MATERIALIZED カラムを使用するか、式を直接埋め込んでください。