通常ビュー
パラメーター化ビュー
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 クエリの結果に一部のカラム名が存在しない場合、たとえそのカラムが Nullable でなくても、ClickHouse はデフォルト値を使用します。materialized view を使用する場合は、すべてのカラムに別名を付けるのが安全です。ClickHouse の materialized view は、どちらかといえば挿入トリガーのように実装されています。ビューのクエリに集約が含まれている場合、それは新たに挿入されたデータのバッチに対してのみ適用されます。ソーステーブルの既存データに対する変更 (update、delete、drop partition など) によって materialized view が変更されることはありません。ClickHouse の materialized view は、エラー発生時の動作が決定論的ではありません。つまり、すでに書き込まれた block は宛先テーブルに保持されますが、エラー発生後の block は保持されません。デフォルトでは、いずれかのビューへの push に失敗すると、INSERT クエリも失敗し、一部の block が宛先テーブルに書き込まれない可能性があります。これは materialized_views_ignore_errors 設定 (INSERT クエリに対して設定する必要があります) で変更できます。materialized_views_ignore_errors=true を設定すると、ビューへの push 中に発生したエラーはすべて無視され、すべての block が宛先テーブルに書き込まれます。また、system.*_log テーブルでは materialized_views_ignore_errors がデフォルトで true に設定されていることにも注意してください。POPULATE を指定すると、既存のテーブルデータは、CREATE TABLE ... AS SELECT ... を実行した場合と同様に、作成時にビューへ挿入されます。指定しない場合、クエリにはビューの作成後にテーブルへ挿入されたデータのみが含まれます。ビューの作成中にテーブルへ挿入されたデータはビューに挿入されないため、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 は単純なインターバルの列です。
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 は存在しません。)
さらに、CREATE クエリで EMPTY が指定されていない限り、materialized view の作成直後に refresh が開始されます。EMPTY が指定されている場合、最初の refresh はスケジュールに従って実行されます。
Replicated DB 内で
APPEND モードでは、SETTINGS all_replicas = 1 を使用して協調を無効にできます。これにより、各レプリカは互いに独立してリフレッシュを実行します。この場合、ReplicatedMergeTree は必須ではありません。
APPEND 以外のモードでは、協調されたリフレッシュのみがサポートされます。協調なしで行うには、Atomic データベースと CREATE ... ON CLUSTER クエリを使用して、すべてのレプリカにリフレッシャブルmaterialized view を作成してください。
協調は Keeper を通じて行われます。znode path は default_replica_path サーバー設定によって決まります。
リフレッシュの依存関係
DEPENDS ON は、異なるテーブル間のリフレッシュを同期します。たとえば、2 つのリフレッシャブルmaterialized view からなる一連の連鎖があるとします。
DEPENDS ON がない場合、両方のビューは深夜にリフレッシュを開始するため、通常 destination には source の前日のデータが反映されます。依存関係を追加すると:
destination の refresh はその日の source の refresh が完了してから初めて開始されるため、destination は最新のデータに基づくことになります。
あるいは、同じ結果は次の方法でも得られます。
1 HOUR には、source のリフレッシュ間隔より短い任意の期間を指定できます。依存先のテーブルが、その依存先のいずれよりも高い頻度でリフレッシュされることはありません。これは、実際のリフレッシュ間隔を複数回指定せずに、リフレッシュ可能なビューのチェーンを設定する有効な方法です。
さらにいくつか例を示します。
REFRESH EVERY 1 DAY OFFSET 10 MINUTE(destination) はREFRESH EVERY 1 DAY(source) に依存します。
sourceのリフレッシュに 10 分以上かかる場合、destinationはそれを待ちます。REFRESH EVERY 1 DAY OFFSET 1 HOURはREFRESH EVERY 1 DAY OFFSET 23 HOURに依存します。
対応するリフレッシュが異なる暦日に発生する場合でも、考え方は上記と同じです。X+1日目のdestinationのリフレッシュは、X日目のsourceのリフレッシュを待ちます (2 時間以上かかる場合) 。REFRESH EVERY 2 HOURはREFRESH EVERY 1 HOURに依存します。
2 HOURのリフレッシュは、1 時間おきのリフレッシュのうち 1 回おきに1 HOURのリフレッシュの後で発生します。たとえば、深夜の リフレッシュの後、次に午前 2 時のリフレッシュの後、という具合です。REFRESH EVERY 1 MINUTEはREFRESH EVERY 2 HOURに依存します。
destinationはsourceがリフレッシュされるたびに 1 回、つまり 2 時間ごとにリフレッシュされます。1 MINUTEは実質的に無視されます。REFRESH AFTER 1 HOURはREFRESH AFTER 1 HOURに依存します。
現時点では、これは推奨されません。
DEPENDS ON は、リフレッシャブルmaterialized view間でのみ機能します。通常のテーブルを DEPENDS ON の一覧に含めると、そのビューはまったくリフレッシュされなくなります (依存関係は ALTER で削除できます。詳細は Changing Refresh Parameters を参照してください) 。リフレッシュ設定
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。prefer_dependency_replica- ビューにDEPENDS ONがある場合、親のリフレッシュを実行したレプリカが、依存先のリフレッシュ実行でも優先されます。ほかのレプリカは、prefer_dependency_replica_delay_msの分だけ試行を遅らせます。SharedMergeTreeと組み合わせると、レプリケーションラグによって依存リフレッシュの連鎖でデータ欠落が発生するのを防ぐのに役立ちます。デフォルト:false。prefer_dependency_replica_delay_ms-prefer_dependency_replicaが有効な場合に、優先されないレプリカが依存先のリフレッシュ実行を試みるまでの待機時間です。デフォルト: 2000 ms。
リフレッシュパラメータの変更
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) を参照している場合、そのデータは一時テーブルと同様に、分散クエリの実行中にリモートサーバーへ転送されることがあります。