通常ビュー
パラメーター化ビュー
Materialized View
OR REPLACE と IF NOT EXISTS は相互に排他的であり、組み合わせると構文エラーになります。
CREATE OR REPLACE MATERIALIZED VIEW
CREATE OR REPLACE MATERIALIZED VIEW は、既存のmaterialized viewと、その内部ストレージテーブル (存在する場合) をアトミックに置き換えます。この操作には、Atomic または Replicated データベースエンジンが必要です。
TO句なし: 古い内部テーブルは削除され、新しい内部テーブルが作成されます。POPULATEが指定されていない限り、内部テーブル内の既存データは失われます。TO句あり: 置き換えられるのはビュー定義のみです。ターゲットテーブルとそのデータには影響しません。REFRESH、ON CLUSTER、およびすべてのエンジンオプションに対応しています。POPULATEはAtomicデータベースでのみサポートされ、Replicatedデータベースでは使用できません (以下のPOPULATEに関する注記を参照) 。CREATE VIEW権限とDROP VIEW権限が必要です。
CREATE OR REPLACE MATERIALIZED VIEW は、Atomic または Replicated データベースエンジンでのみサポートされます。Ordinary データベースエンジンではサポートされません。TO [db].[table] を指定せずに materialized view を作成する場合は、データを格納するためのテーブルエンジンである ENGINE を指定する必要があります。
TO [db].[table] を指定して materialized view を作成する場合は、POPULATE を併用できません。
materialized view は次のように実装されています。SELECT で指定されたテーブルにデータが挿入されると、その挿入データの一部がこの SELECT クエリによって変換され、その結果がビューに挿入されます。
ClickHouse の materialized view は、宛先テーブルへの挿入時にカラム順ではなく カラム名 を使用します。
SELECT クエリの結果に一部のカラム名が含まれていない場合、ClickHouse はそのカラムが Nullable でなくてもデフォルト値を使用します。安全策として、Materialized views を使用する際はすべてのカラムに別名を付けることを推奨します。ClickHouse の materialized view は、insert trigger に近い形で実装されています。view クエリに集約が含まれている場合、それは新たに挿入されたデータのバッチに対してのみ適用されます。source table の既存データに対する変更 (update、delete、drop partition など) は、materialized view には反映されません。ClickHouse の materialized view は、エラー発生時の動作が決定論的ではありません。つまり、すでに書き込まれた blocks は宛先テーブルに保持されますが、エラー発生後の blocks は保持されません。デフォルトでは、いずれかの view への書き込みで例外が発生すると、INSERT クエリは失敗します。その時点までに block がすでに source table に到達しているかどうかは保証されません。これは view 側のエラーではなく、insert pipeline のタイミングに依存します。失敗した INSERT は、挿入の重複排除 (insert_deduplicate、deduplicate_blocks_in_dependent_materialized_views) を有効にして再試行し、source table とそれに依存するすべての views への exactly-once 配信を実現してください。INSERT クエリに materialized_views_ignore_errors=true を設定しても、変わるのはエラー報告だけです。各 view のエラーは警告としてログに記録され、INSERT クエリ自体は成功します。失敗した view の宛先への配信は部分的になります。つまり、例外発生前に処理された blocks は保持され、失敗した block とそれ以降の blocks はその view から破棄されます。その宛先の下流にある views には到達した blocks だけが渡されるため、それらへの配信も部分的になります。例外を発生させなかった sibling view (およびその下流チェーン) には完全に書き込まれ、source table にも通常どおり書き込まれます。INSERT は成功として報告されるため、クライアントには失敗のシグナルが返らず、自動的な再試行もトリガーされません。この設定は、view 側の問題によって source table への書き込みを妨げてはならない場合にのみ使用してください (たとえば system.*_log tables) 。materialized_views_ignore_errors は、system.*_log tables ではデフォルトで true です。POPULATE を指定すると、既存の table データは、CREATE TABLE ... AS SELECT ... を行う場合のように、作成時に view に挿入されます。そうでない場合、クエリに含まれるのは view 作成後に table に挿入されたデータのみです。view の作成中に table に挿入されたデータはそこに挿入されないため、POPULATE の使用は 推奨しません。
POPULATE は CREATE TABLE ... AS SELECT ... のように動作するため、いくつかの制限があります。- Replicated database ではサポートされていません
- ClickHouse Cloud ではサポートされていません
INSERT ... SELECT を使用できます。SELECT クエリには DISTINCT、GROUP BY、ORDER BY、LIMIT を含めることができます。対応する変換は、挿入されるデータの各ブロックごとに独立して実行される点に注意してください。たとえば、GROUP BY が設定されている場合、データは挿入時に集約されますが、それは挿入データの単一のパケット内でのみ行われます。データがその後さらに集約されることはありません。例外は、SummingMergeTree のように、データ集約を独自に実行する ENGINE を使用する場合です。
materialized view が TO [db.]name 構文を使用している場合は、その view を DETACH し、ターゲットテーブルに対して ALTER を実行したあとで、先ほどデタッチした (DETACH) view を ATTACH できます。
materialized view は optimize_on_insert 設定の影響を受ける点に注意してください。データは view に挿入される前にマージされます。
view は通常の table と同じように見えます。たとえば、SHOW TABLES クエリの結果にも表示されます。
view を削除するには、DROP VIEW を使用します。ただし、DROP TABLE も VIEW に対して機能します。
SQL security
DEFINER と SQL SECURITY を使うと、ビューの基になるクエリを実行する際に、どの ClickHouse ユーザーを使用するかを指定できます。
SQL SECURITY には、DEFINER、INVOKER、NONE の 3 つの有効な値があります。DEFINER 句では、既存の任意のユーザー、または CURRENT_USER を指定できます。
次の表は、ビューから読み取るために、どのユーザーにどの権限が必要かを示しています。
なお、SQL security オプションにかかわらず、どの場合でもビューを読み取るには GRANT SELECT ON <view> が引き続き必要です。
| SQL security option | View | Materialized View |
|---|---|---|
DEFINER alice | alice は、ビューのソーステーブルに対する SELECT 権限を持っている必要があります。 | alice は、ビューのソーステーブルに対する SELECT 権限と、ビューのターゲットテーブルに対する INSERT 権限を持っている必要があります。 |
INVOKER | ユーザーは、ビューのソーステーブルに対する SELECT 権限を持っている必要があります。 | materialized view には SQL SECURITY INVOKER を指定できません。 |
NONE | - | - |
SQL SECURITY NONE は非推奨のオプションです。SQL SECURITY NONE を指定してビューを作成する権限を持つユーザーは、任意のクエリを実行できてしまいます。
そのため、このオプションでビューを作成するには GRANT ALLOW SQL SECURITY NONE TO <user> が必要です。DEFINER/SQL SECURITY が指定されていない場合は、デフォルト値が使用されます。
SQL SECURITY: 通常のビューではINVOKER、materialized view ではDEFINER(設定で変更可能)DEFINER:CURRENT_USER(設定で変更可能)
DEFINER/SQL SECURITY を指定せずにビューがアタッチされた場合、デフォルト値は materialized view では SQL SECURITY NONE、通常のビューでは SQL SECURITY INVOKER です。
既存のビューの SQL security を変更するには、次を使用します。
例
Live View
リフレッシャブルmaterialized view
interval は単純なインターバルの列です。
REFRESH clause では、EVERY、AFTER、DEPENDS ON の少なくとも 1 つを指定する必要があります。これらを 1 つも指定しない単独の REFRESH は拒否されます。EVERY/AFTER を伴わない REFRESH DEPENDS ON ... は、REFRESH AFTER 0 SECOND DEPENDS ON ... の省略形です。詳細は以下の Refresh Dependencies を参照してください。
対応するクエリを定期的に実行し、その結果をテーブルに格納します。
APPENDが指定されている場合、各リフレッシュでは既存の行を削除せずにテーブルへ行を挿入します。この insert は、通常のINSERT INTO ... SELECTクエリと同様にアトミックではありません。- それ以外の場合、各リフレッシュでテーブルの以前の内容はアトミックに置き換えられます。
- insert trigger はありません。
SELECTで指定したテーブルに新しいデータが挿入されても、そのデータがリフレッシャブルmaterialized view に自動的に反映されることは ありません。代わりに、データの挿入は定期実行または手動実行のリフレッシュ時にのみ行われます。 SELECTクエリには制約がありません。テーブル関数 (例:url()) 、ビュー、UNION、JOIN はいずれも使用できます。
クエリの
REFRESH ... SETTINGS 部分で指定する設定はリフレッシュ設定 (例: refresh_retries) であり、通常の設定 (例: max_threads) とは異なります。通常の設定は、クエリ末尾の SETTINGS で指定できます。リフレッシュ スケジュール
RANDOMIZE FOR は、各リフレッシュの時刻をランダムに調整します。例:
REFRESH EVERY 1 MINUTE を設定したビューの refresh に 2 分かかる場合、実際の refresh 間隔は 2 分になります。その後、処理が速くなって 10 秒で refresh できるようになれば、再び 1 分ごとの refresh に戻ります。 (つまり、実行されなかった refresh の遅れを取り戻すために 10 秒ごとに refresh されることはありません。そのような未実行分の backlog は存在しません。)
通常、最初の refresh は materialized view の作成直後に開始されます。前回の refresh からの経過時間は無限大であるため、どのスケジュールでも「今すぐ refresh すべき時刻」と判断されるからです。EMPTY が指定されている場合、この初回の refresh はスキップされ、最初の refresh は次にスケジュールされた時刻に実行されます。たとえば EVERY 1 HOUR では、最初の refresh は現在の時刻のちょうど1時間の区切りで実行されます。
Replicated DB 内で
APPEND モードでは、SETTINGS all_replicas = 1 を使用して協調を無効にできます。これにより、各レプリカは互いに独立してリフレッシュを実行します。この場合、ReplicatedMergeTree は必須ではありません。
APPEND 以外のモードでは、協調されたリフレッシュのみがサポートされます。協調なしで行うには、Atomic データベースと CREATE ... ON CLUSTER クエリを使用して、すべてのレプリカにリフレッシャブルmaterialized view を作成してください。
協調は Keeper を通じて行われます。znode path は default_replica_path サーバー設定によって決まります。
リフレッシュの依存関係
DEPENDS ON は、異なるテーブルのリフレッシュを同期します:
DEPENDS ON は、リフレッシャブルmaterialized view 間でのみ機能します。特に、依存先のビューが TO <table> を使用している場合は、テーブル名ではなくビュー名を使用してください。DEPENDS ON のリストに通常のテーブルやリフレッシャブルでないビューが含まれている場合、またはタイプミスがある場合、そのビューはリフレッシュされず、system.view_refreshes に状態 MissingDependencies と表示されます。依存関係は ALTER を使用して変更または削除できます。詳しくは リフレッシュパラメータの変更 を参照してください。伝播レイテンシを一定に保つための DEPENDS ON の使用
REFRESH EVERY を使用している場合、依存関係は各時間スロットに適用されます。
たとえば、ビュー X と Y がどちらも REFRESH EVERY 1 HOUR を使用し、Y が X の出力テーブルを読み取るとします。依存関係がない場合、Y は通常、前の時間のリフレッシュで生成された X のデータを参照します。DEPENDS ON X を使用すると、Y の 11:00 のリフレッシュは、X の 11:00 のリフレッシュが完了した後にのみ開始されます。
バッチ単位のストリーム処理での DEPENDS ON の使用
REFRESH EVERY を使用しない場合、依存するビュー X は、X の前回のリフレッシュ以降に、そのすべての依存関係が少なくとも 1 回リフレッシュされていればリフレッシュされます。REFRESH AFTER T は遅延を追加するもので、依存先は依存元のリフレッシュ完了から T 時間後にリフレッシュを開始します。
循環依存は許可されており、有用でもあります。次のリフレッシャブルmaterialized view のグラフを考えてみましょう。
- X はある stream から行の batch を取り出し、それをテーブルに格納します。
- 次に、Y と Z はどちらもそのテーブルを読み取り、異なる集計を行って、結果を別のテーブルに追記します。
- batch の処理が完了すると、X は次の batch を取り出し、この cycle が繰り返されます。
SYSTEM REFRESH VIEW を実行する必要があります。
リフレッシュ設定
refresh_retries- リフレッシュクエリが例外で失敗した場合に、再試行する回数を指定します。すべての再試行が失敗した場合は、次にスケジュールされているリフレッシュ時刻までスキップします。0 は再試行なし、-1 は無制限の再試行を意味します。デフォルト: 2。refresh_retry_initial_backoff_ms-refresh_retriesが 0 でない場合の、最初の再試行までの待機時間です。以降の再試行では、待機時間が回ごとに 2 倍になり、最大でrefresh_retry_max_backoff_msまで増加します。デフォルト: 100 ms。refresh_retry_max_backoff_ms- リフレッシュ試行の間隔が指数的に増加する際の上限です。デフォルト: 60000 ms (1 分) 。all_replicas-APPENDを使用する Replicated database で、すべてのレプリカが独立してリフレッシュするか、スケジュール時刻ごとに 1 つのレプリカだけがリフレッシュするかを制御します。ビューの作成後は変更できません。デフォルト:false。
リフレッシュパラメータの変更
ALTER TABLE ... MODIFY REFRESHを使って変更します。
EVERY または AFTER) の指定は必須です。このステートメントでは、リフレッシュに関するすべてのパラメーター (スケジュール、RANDOMIZE FOR、DEPENDS ON、およびリフレッシュ設定) が、指定した内容で常に丸ごと置き換えられます。省略した項目は、設定であればデフォルト値に戻され、依存関係やランダム化であれば削除されます。
-
リフレッシュ設定のみを変更するには (例:
refresh_retries) 、現在のスケジュールを再度指定してください。 -
ALTER TABLE ... MODIFY SETTING refresh_retries = ...は materialized view ではサポートされていません。必ずMODIFY REFRESHを使用してください。 -
APPENDの追加または削除はサポートされていません。 -
all_replicas設定は作成後に変更できません。
その他の操作
system.view_refreshesで確認できます。特に、リフレッシュの進行状況 (実行中の場合) 、前回および次回のリフレッシュ時刻、リフレッシュが失敗した場合の例外メッセージが含まれます。
手動でリフレッシュを停止、開始、トリガー、またはキャンセルするには、SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEWを使用します。
リフレッシュの完了を待機するには、SYSTEM WAIT VIEWを使用します。特に、ビューの作成後に初回リフレッシュが完了するのを待つ際に便利です。
豆知識: リフレッシュクエリは、現在リフレッシュ中のビューから読み取ることができ、その際にはリフレッシュ前のバージョンのデータを参照します。つまり、Conway’s Game of Life を実装できます: https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==
ウィンドウビュー
これは実験的な機能であり、今後のリリースで後方互換性のない変更が行われる可能性があります。ウィンドウビュー と
WATCH クエリを使用するには、allow_experimental_window_view 設定を有効にしてください。set allow_experimental_window_view = 1 コマンドを実行します。WATCH クエリを使用して通知を送信したりできます。
ウィンドウビュー の作成は、MATERIALIZED VIEW の作成に似ています。ウィンドウビュー では、中間データを保存するための内部ストレージエンジンが必要です。内部ストレージは INNER ENGINE 句を使用して指定でき、ウィンドウビュー はデフォルトの内部エンジンとして AggregatingMergeTree を使用します。
TO [db].[table] なしで ウィンドウビュー を作成する場合は、データを保存するためのテーブルエンジンである ENGINE を指定する必要があります。
時間ウィンドウ関数
時間属性
time_attr にテーブルのカラムを指定するか、now() 関数を使用することで定義できます。次のクエリは、処理時間を使用するウィンドウビューを作成します。
WATERMARK 構文を使用してイベント時刻処理をサポートします。
ウィンドウビュー には、3 つのウォーターマーク戦略があります。
STRICTLY_ASCENDING: これまでに観測された最大のタイムスタンプのウォーターマークを出力します。タイムスタンプが最大タイムスタンプより小さい行は、遅延データとは見なされません。ASCENDING: これまでに観測された最大のタイムスタンプから 1 を引いたウォーターマークを出力します。タイムスタンプが最大タイムスタンプ以下の行は、遅延データとは見なされません。BOUNDED: WATERMARK=INTERVAL。これまでに観測された最大のタイムスタンプから指定した遅延を引いたウォーターマークを出力します。
WATERMARK を使用して ウィンドウビュー を作成する例です。
ALLOWED_LATENESS=INTERVAL を設定することで遅延イベントの処理をサポートします。遅延処理の例を次に示します。
SELECT クエリは、ALTER TABLE ... MODIFY QUERY ステートメントを使用して変更できます。新しい SELECT クエリによって得られるデータ構造は、TO [db.]name 句の有無にかかわらず、元の SELECT クエリと同じである必要があります。中間状態は再利用できないため、現在の window 内のデータは失われることに注意してください。
新しいウィンドウの監視
TO 構文を使用して結果をテーブルに出力することもできます。
LIMIT で指定できます。EVENTS 句を使うと、WATCH クエリの簡易形式を利用できます。この場合、クエリ結果の代わりに、最新のクエリのウォーターマークだけが返されます。
設定
window_view_clean_interval: 古くなったデータを解放するための、ウィンドウビュー のクリーンアップ間隔 (秒) です。システム時刻またはWATERMARK設定に基づき、まだ完全にはトリガーされていないウィンドウは保持され、それ以外のデータは削除されます。window_view_heartbeat_interval: watchクエリが動作中であることを示すハートビート間隔 (秒) です。wait_for_window_view_fire_signal_timeout: イベント時刻処理において、ウィンドウビュー の fire signal を待機する際のタイムアウトです。
例
data という名前のログテーブルで、10秒ごとのクリックログ数を集計する必要があるとします。テーブル構造は次のとおりです。
WATCH クエリを使用します。
data テーブルにログが挿入されると、
WATCH クエリの結果は次のように表示されます:
TO構文を使用して、出力を別のテーブルに関連付けることもできます。
*window_view* という名前です) 。
ウィンドウビュー の使用法
- 監視: ログのメトリクスを時間ごとに集計・計算し、その結果をターゲットテーブルに出力します。ダッシュボードでは、ターゲットテーブルをソーステーブルとして使用できます。
- 分析: 時間ウィンドウ内のデータを自動的に集計して前処理します。これは、大量のログを分析する場合に役立ちます。前処理により、複数のクエリで同じ計算を繰り返す必要がなくなり、クエリのレイテンシが低減されます。
一時ビュー
- セッション存続期間 一時ビューは現在のセッション中にのみ存在します。セッションが終了すると自動的に削除されます。
- データベースなし 一時ビューをデータベース名で修飾することはできません。一時ビューはデータベースの外側 (セッションのネームスペース) に存在します。
-
レプリケートされない / ON CLUSTER なし
一時オブジェクトはセッションローカルであり、
ON CLUSTERを付けて作成することはできません。 - 名前解決 一時オブジェクト (テーブルまたはビュー) が永続オブジェクトと同じ名前を持ち、クエリがデータベース名を付けずにその名前を参照した場合は、一時オブジェクトが使用されます。
-
論理オブジェクト (ストレージなし)
一時ビューが保持するのは
SELECTテキストのみです (内部的にはViewストレージを使用します) 。データは永続化されず、INSERTも受け付けません。 -
Engine 句
ENGINEを指定する必要はありません。ENGINE = Viewとして指定した場合も、無視されるか、同じ論理ビューとして扱われます。 -
セキュリティ / 権限
一時ビューを作成するには
CREATE TEMPORARY VIEW権限が必要です。この権限はCREATE VIEWによって暗黙的に付与されます。 -
SHOW CREATE
一時ビューの DDL を表示するには、
SHOW CREATE TEMPORARY VIEW view_name;を使用します。
構文
OR REPLACE は、一時テーブルとの整合性を保つため、一時ビューでは サポートされていません。一時ビューを「置き換える」必要がある場合は、いったん削除してから再作成してください。
例
使用不可 / 制限事項
CREATE OR REPLACE TEMPORARY VIEW ...→ 使用できません (DROP+CREATEを使用してください) 。CREATE TEMPORARY MATERIALIZED VIEW .../WINDOW VIEW→ 使用できません。CREATE TEMPORARY VIEW db.view AS ...→ 使用できません (データベース修飾子は指定できません) 。CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...→ 使用できません (一時オブジェクトはセッションローカルです) 。POPULATE,REFRESH,TO [db.table], 内部エンジン、および MV 固有の句は、一時ビューには 適用されません。
分散クエリに関する注意事項
Memory) を参照している場合、そのデータは一時テーブルと同様に、分散クエリの実行中にリモートサーバーへ転送されることがあります。