物化ビューとプロジェクション
ユーザーからの一般的な質問は、マテリアライズドビューを使用すべきか、それともプロジェクションを使用すべきかということです。この記事では、両者の主な違いと、特定のシナリオでどちらかを選択する理由について探ります。
主な違いの概要
以下の表は、考慮すべきさまざまな側面におけるマテリアライズドビューとプロジェクションの主な違いをまとめたものです。
課題 | マテリアライズドビュー | プロジェクション |
---|---|---|
データの保存と場所 | 別の明示的なターゲットテーブルに結果を保存し、ソーステーブルへの挿入時に挿入トリガーとして機能します。 | プロジェクションは、物理的にメインテーブルデータと一緒に保存された最適化されたデータレイアウトを作成し、ユーザーには見えません。 |
更新メカニズム | ソーステーブルへのINSERT に対して同期的に操作します(インクリメンタルマテリアライズドビューの場合)。注:リフレッシュ可能なマテリアライズドビューを使用してスケジュールすることもできます。 | メインテーブルへのINSERT に応じて、非同期的にバックグラウンドで更新されます。 |
クエリの相互作用 | マテリアライズドビューを使用する場合、ターゲットテーブルを直接クエリする必要があります。これは、ユーザーがクエリを記述する際にマテリアライズドビューの存在を認識する必要があることを意味します。 | プロジェクションは、ClickHouseのクエリオプティマイザーによって自動的に選択され、ユーザーがプロジェクションを利用するためにテーブルを修正する必要がないという点で透明です。バージョン25.6からは、複数のプロジェクションでのフィルタリングも可能です。 |
UPDATE / DELETE の処理 | マテリアライズドビューは、ソーステーブルに対するUPDATE やDELETE 操作に自動的に反応しません。これは、マテリアライズドビューがソーステーブルの知識を持たず、ソーステーブルへの挿入トリガーとしてのみ機能するためです。これにより、ソースとターゲットテーブル間のデータの古さが発生する可能性があり、ワークアラウンドや定期的な完全リフレッシュが必要になります。(リフレッシュ可能マテリアライズドビュー経由)。 | デフォルトでは、DELETED 行と互換性がありません(特に軽量削除)。lightweight_mutation_projection_mode (v24.7+)を使用すると互換性が有効になります。 |
JOIN サポート | あり。リフレッシュ可能なマテリアライズドビューは、複雑な非正規化に使用できます。インクリメンタルマテリアライズドビューは、左端のテーブル挿入時にのみトリガーされます。 | なし。プロジェクション定義内でマテリアライズデータをフィルタリングするためのJOIN 操作はサポートされていません。 |
定義内のWHERE 句 | はい。マテリアライゼーション前にデータをフィルタリングするために、WHERE 句を含めることができます。 | いいえ。プロジェクション定義内では、マテリアル化されたデータをフィルタリングするためにWHERE 句はサポートされていません。 |
チェイニング機能 | はい。一つのマテリアライズドビューのターゲットテーブルを他のマテリアライズドビューのソースにすることができ、多段階のパイプラインを可能にします。 | いいえ。プロジェクションはチェーンできません。 |
適用可能なテーブルエンジン | 様々なソーステーブルエンジンで使用できますが、ターゲットテーブルは通常MergeTree ファミリーです。 | MergeTree ファミリーのテーブルエンジンにのみ利用可能です。 |
障害処理 | データ挿入中に障害が発生すると、ターゲットテーブルのデータが失われ、潜在的な不整合が生じます。 | 障害はバックグラウンドで静かに処理されます。クエリはマテリアライズされた部分と非マテリアライズ部分をシームレスに混ぜることができます。 |
運用オーバーヘッド | 明示的なターゲットテーブルの作成と、しばしば手動でのバックフィリングが必要です。UPDATE /DELETE に伴う一貫性の管理は、複雑さを増します。 | プロジェクションは自動的に維持され、同期され、一般的に運用上の負担が軽くなります。 |
FINAL クエリの互換性 | 一般的に互換性がありますが、ターゲットテーブルでGROUP BY が必要な場合が多いです。 | FINAL クエリでは機能しません。 |
レイジーマテリアライゼーション | はい。 | マテリアライゼーション機能を使用する際には、プロジェクションの互換性の問題を監視する必要があります。query_plan_optimize_lazy_materialization = false を設定する必要があるかもしれません。 |
並列レプリカ | はい。 | いいえ。 |
optimize_read_in_order | はい。 | はい。 |
軽量更新および削除 | はい。 | いいえ。 |
マテリアライズドビューとプロジェクションの比較
マテリアライズドビューを選択する場合
マテリアライズドビューを使用することを検討すべき場合は以下の通りです。
- リアルタイムETLおよび多段階データパイプラインを使用している:複雑な変換や集計を実行する必要がある、あるいはデータが到着するにつれて複数の段階を経由してルーティングする必要があります。ビューをチェインすることができます。
- 複雑な非正規化が必要です:複数のソース(テーブル、サブクエリまたは辞書)からデータを事前に結合して、単一のクエリ最適化テーブルにする必要がある、特にリフレッシュ可能なマテリアライズドビューを使用して定期的な完全リフレッシュが許容される場合。
- 明示的なスキーマ制御が必要:独自のスキーマとエンジンを持つ明示的なターゲットテーブルが必要で、事前に計算された結果のためのデータモデリングに柔軟性を提供します。
- インジェスト時にフィルタリングしたい:データがマテリアライズされる前にフィルタリングする必要があり、ターゲットテーブルに書き込まれるデータ量を減らします。
マテリアライズドビューを避けるべき場合
マテリアライズドビューの使用を避けるべき場合は以下を考慮するべきです。
- ソースデータが頻繁に更新または削除される:ソースとターゲットテーブル間の一貫性を処理するための追加の戦略がない場合、インクリメンタルマテリアライズドビューは古くなり、一貫性がなくなる可能性があります。
- シンプルさと自動最適化が好まれる:別のターゲットテーブルの管理を避けたい場合。
プロジェクションを選択する場合
プロジェクションを使用することを考慮すべき場合は以下の通りです。
- 単一のテーブルのクエリを最適化する:主な目標は、代替のソート順を提供し、主キーに含まれないカラムのフィルタを最適化し、単一テーブルに対して集計を事前計算することで、単一の基本テーブルに対するクエリを高速化することです。
- クエリの透明性が重要:クエリが修正なしで元のテーブルを対象にしたい場合、ClickHouseに最適なデータレイアウトを選択させたいです。
プロジェクションを避けるべき場合
プロジェクションの使用を避けるべき場合は以下があります。
- 複雑なデータ変換または多段階ETLが必要:プロジェクションは、その定義内での
JOIN
操作をサポートしていないため、多段階パイプラインの構築や、ウィンドウ関数や複雑なCASE
ステートメントのハンドリングができません。このため、複雑なデータ変換には適していません。 - マテリアライズされたデータの明示的なフィルタリングが必要:プロジェクションは、その定義内においてデータをマテリアライズするときのフィルタリングのために
WHERE
句をサポートしていません。 - 非MergeTreeテーブルエンジンが使用されている:プロジェクションは
MergeTree
ファミリーのエンジンを使用するテーブルのみに独占的に利用可能です。 FINAL
クエリが重要:プロジェクションは、重複排除に使用されることがあるFINAL
クエリでは機能しません。- プロジェクションではサポートされないため、並列レプリカが必要です。
概要
マテリアライズドビューとプロジェクションは、クエリの最適化とデータ変換のための強力なツールであり、一般的にはそれらを相互排他的な選択肢と考えるべきではありません。代わりに、クエリから最大限の効果を得るために、補完的に使用することができます。そのため、ClickHouseにおけるマテリアライズドビューとプロジェクションの選択は、実際には特定のユースケースやアクセスパターンに依存します。
一般的な指針として、1つまたは複数のソーステーブルからターゲットテーブルにデータを集計したり、大規模な複雑な変換を実行したりする必要がある場合は、マテリアライズドビューを使用することを検討すべきです。マテリアライズドビューは、クエリ時間から挿入時間への高価な集計の作業を移行するために優れています。それらは、日次または月次のロールアップ、リアルタイムのダッシュボード、またはデータ要約などに優れた選択肢です。
一方で、テーブルの主キーに使用されるカラムとは異なるカラムでフィルタリングするクエリを最適化する必要がある場合はプロジェクションを使用するべきです。主キーが変更不可能になった場合や、アクセスパターンが主キーが対応できるよりも多様である場合には特に便利です。