マテリアライズドビューを使用する
ClickHouse は 2 種類のマテリアライズドビューをサポートしています。具体的には、インクリメンタル と リフレッシャブル です。どちらも事前計算と結果の保存によりクエリを高速化することを目的としていますが、基盤となるクエリが「いつ」「どのように」実行されるか、どのようなワークロードに適しているか、そしてデータの鮮度をどのように扱うかといった点で大きく異なります。
型に関するベストプラクティス や 主キー最適化 が実施済みであることを前提として、高速化が必要な特定のクエリパターンに対してマテリアライズドビューの利用を検討してください。
インクリメンタルマテリアライズドビュー はリアルタイムに更新されます。新しいデータがソーステーブルに挿入されると、ClickHouse は自動的にマテリアライズドビューのクエリを新しいデータブロックに適用し、その結果を別のターゲットテーブルに書き込みます。時間の経過とともに、ClickHouse はこれらの部分的な結果をマージして、完全かつ最新のビューを生成します。このアプローチは、計算コストを挿入時に移し、新しいデータのみを処理するため非常に効率的です。その結果、ターゲットテーブルに対する SELECT クエリは高速かつ軽量になります。インクリメンタルビューはすべての集約関数をサポートし、各クエリは挿入対象となるデータセットの直近の小さなサブセットのみを処理するため、ペタバイト規模のデータに対しても高いスケーラビリティを発揮します。

リフレッシャブルマテリアライズドビュー は対照的に、スケジュールに従って更新されます。これらのビューは、一定間隔でクエリ全体を再実行し、その結果でターゲットテーブルの内容を上書きします。これは、Postgres のような従来の OLTP データベースにおけるマテリアライズドビューと似ています。

インクリメンタルマテリアライズドビューとリフレッシャブルマテリアライズドビューのどちらを選択するかは、主にクエリの性質、データがどの程度の頻度で変化するか、ビューの更新が各行の挿入を逐次反映する必要があるのか、それとも定期的なリフレッシュで十分なのかに大きく依存します。これらのトレードオフを理解することは、ClickHouse で高性能かつスケーラブルなマテリアライズドビューを設計するうえで重要です。
インクリメンタルマテリアライズドビューを使用するタイミング
インクリメンタルマテリアライズドビューは、一般的に推奨される選択肢です。ソーステーブルに新しいデータが投入されるたびにリアルタイムで自動的に更新されます。すべての集約関数をサポートしており、特に単一テーブルに対する集約で高い効果を発揮します。挿入時に結果をインクリメンタルに計算することで、クエリは大幅に小さいデータサブセットに対して実行されるため、ペタバイト級のデータに対しても容易にスケールできます。多くの場合、クラスタ全体のパフォーマンスに顕著な影響を及ぼすこともありません。
次のような場合にはインクリメンタルマテリアライズドビューを使用してください。
- すべての挿入に応じて更新されるリアルタイムなクエリ結果が必要な場合
- 大量のデータを頻繁に集約またはフィルタリングする場合
- クエリが単一テーブルに対する単純な変換や集約で構成されている場合
インクリメンタルマテリアライズドビューの例についてはこちらを参照してください。
リフレッシュ可能なマテリアライズドビューを使用すべき場合
リフレッシュ可能なマテリアライズドビューは、増分更新ではなく定期的にクエリを実行し、そのクエリ結果セットを保存して高速な取得を可能にします。
クエリ性能が極めて重要(例: サブミリ秒レイテンシ)で、多少結果が古くても許容できる場合に最も有用です。クエリは毎回全件を再実行するため、リフレッシュ可能なビューは、計算が比較的高速に完了するクエリ、あるいは比較的まれな間隔(例: 1時間ごと)で計算すればよいクエリに最適です。典型的な例としては、「トップ N」結果のキャッシュやルックアップテーブルなどがあります。
実行頻度は、システムへの過剰な負荷を避けるよう慎重に調整する必要があります。リソース消費量の大きい非常に複雑なクエリは注意深くスケジューリングすべきです。これらはキャッシュへの影響や CPU・メモリの消費により、クラスタ全体のパフォーマンス低下を引き起こす可能性があります。クエリは、クラスタの過負荷を防ぐため、リフレッシュ間隔と比較して十分に短時間で完了することが望まれます。例えば、クエリ自体の計算に少なくとも 10 秒かかる場合、そのビューを 10 秒ごとに更新するようスケジュールしてはいけません。
まとめ
まとめると、リフレッシュ可能なマテリアライズドビューは次のような場合に使用します。
- キャッシュされたクエリ結果を即時に利用したいが、鮮度のわずかな遅延は許容できる場合。
- クエリ結果セットの上位 N 件が必要な場合。
- 結果セットのサイズが時間とともに際限なく増加しない場合。そうなると対象ビューのパフォーマンスが低下します。
- 複数テーブルを含む複雑な
JOINや正規化解除を行っており、いずれかのソーステーブルが変更されるたびに更新が必要な場合。 - バッチワークフロー、正規化解除タスク、または dbt の DAG に類似したビュー依存関係を構築している場合。
リフレッシュ可能なマテリアライズドビューの例についてはこちらを参照してください。
APPEND モードと REPLACE モード
リフレッシュ可能なマテリアライズドビューは、対象テーブルへのデータ書き込みで APPEND と REPLACE の 2 つのモードをサポートします。これらのモードは、ビューをリフレッシュした際にビューのクエリ結果がどのように書き込まれるかを定義します。
REPLACE がデフォルトの動作です。ビューがリフレッシュされるたびに、対象テーブルの既存の内容は最新のクエリ結果で完全に上書きされます。これは、結果セットのキャッシュなど、ビューが常に最新状態を反映すべきユースケースに適しています。
APPEND は対照的に、内容を置き換えるのではなく、新しい行を対象テーブルの末尾に追加することを可能にします。これにより、定期的なスナップショットの取得など、追加のユースケースが可能になります。APPEND は、各リフレッシュが異なる時点を表す場合や、結果を履歴として蓄積したい場合に特に有用です。
APPEND モードを選択するのは次のような場合です。
- 過去のリフレッシュ履歴を保持したい場合。
- 定期的なスナップショットやレポートを構築している場合。
- 時間とともにリフレッシュ結果を増分的に収集する必要がある場合。
REPLACE モードを選択するのは次のような場合です。
- 直近の結果のみが必要な場合。
- 古いデータを完全に破棄すべき場合。
- ビューが現在の状態やルックアップを表している場合。
APPEND 機能の具体的な活用例は、Medallion アーキテクチャを構築するケースで確認できます。