通常ビュー
構文:パラメーター化ビュー
パラメーター化ビューは通常のビューに似ていますが、すぐには評価されないパラメーターを指定して作成できます。 これらのビューはテーブル関数として使用でき、その際はビュー名を関数名として、パラメーター値を引数として指定します。system.columns テーブルにはパラメーター化ビューに関する情報はありません。
また、DESCRIBE クエリはパラメーターが指定されている場合にのみ機能します。
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 を使用して既存のソースデータからターゲットテーブルをバックフィルすることもできます (ターゲットテーブルにすでにデータが含まれている場合、バックフィルされた行は追加されます) 。POPULATE は REFRESH と併用できません。リフレッシャブルmaterialized view は最初のリフレッシュでデータが補完されるため、POPULATE を使用すると初期データが二重にロードされます (代わりに、最初のリフレッシュをスキップするには EMPTY を使用してください) 。
materialized view は次のように実装されています。SELECT で指定されたテーブルにデータが挿入されると、その挿入データの一部がこの SELECT クエリによって変換され、その結果がビューに挿入されます。
ClickHouse の materialized VIEW は、宛先テーブルへの挿入時にカラム順ではなく カラム名 を使用します。
SELECT クエリの結果に一部のカラム名が含まれていない場合、ClickHouse はそのカラムが Nullable でなくてもデフォルト値を使用します。安全策として、Materialized VIEWs を使用する際はすべてのカラムに別名を付けることを推奨します。ClickHouse の materialized VIEW は、insert trigger に近い形で実装されています。VIEW クエリに集約が含まれている場合、それは新たに挿入されたデータのバッチに対してのみ適用されます。ソーステーブル の既存データに対する変更 (update、delete、drop partition など) は、materialized VIEW には反映されません。ClickHouse の materialized VIEW は、エラー発生時の動作が決定論的ではありません。つまり、すでに書き込まれた blocks は宛先テーブルに保持されますが、エラー発生後の blocks は保持されません。デフォルトでは、いずれかの VIEW への書き込みで例外が発生すると、INSERT クエリは失敗します。その時点までに block がすでに ソーステーブル に到達しているかどうかは保証されません。これは VIEW 側のエラーではなく、insert pipeline のタイミングに依存します。失敗した INSERT は、挿入の重複排除 (insert_deduplicate、deduplicate_blocks_in_dependent_materialized_views) を有効にして再試行し、ソーステーブル とそれに依存するすべての VIEWs への exactly-once 配信を実現してください。INSERT クエリに materialized_views_ignore_errors=true を設定しても、変わるのはエラー報告だけです。各 VIEW のエラーは警告としてログに記録され、INSERT クエリ自体は成功します。失敗した VIEW の宛先への配信は部分的になります。つまり、例外発生前に処理された blocks は保持され、失敗した block とそれ以降の blocks はその VIEW から破棄されます。その宛先の下流にある VIEWs には到達した blocks だけが渡されるため、それらへの配信も部分的になります。例外を発生させなかった sibling VIEW (およびその下流チェーン) には完全に書き込まれ、ソーステーブル にも通常どおり書き込まれます。INSERT は成功として報告されるため、クライアントには失敗のシグナルが返らず、自動的な再試行もトリガーされません。この設定は、VIEW 側の問題によって ソーステーブル への書き込みを妨げてはならない場合にのみ使用してください (たとえば system.*_log tables) 。materialized_views_ignore_errors は、system.*_log tables ではデフォルトで true です。POPULATE を指定すると、既存のソーステーブルのデータは、作成時に VIEW に挿入されます。そうでない場合、VIEW に含まれるのは、VIEW の作成後にソーステーブルに挿入されたデータのみです。
通常の CREATE MATERIALIZED VIEW では、POPULATE はデフォルトで アトミック です (設定 materialized_views_populate_atomically = 1) 。ソーステーブルへの新規挿入に VIEW がサブスクライブされ、既存データのスナップショットが、ソーステーブルに対する短時間の排他ロックのもとで同時に取得されます。これにより、データ投入と同時に挿入されたすべての行は、欠落も重複もなく VIEW に 正確に一度だけ 配信されます。その後、 (長時間実行される可能性がある) データ投入では、ロックを保持せずに固定されたスナップショットを読み取ります。
これはローカルな挿入パスのアトミック性です。排他ロックは、同じサーバー上でこのソーステーブルのストレージロックを取得する挿入とのみ直列化されるため、exactly-once 保証の対象はこのサーバー経由で到着する挿入です。これはクラスター全体の保証ではありません。データ投入と同時に ReplicatedMergeTree ソースの別のレプリカに挿入された行や、分散書き込みパス (たとえば Distributed table への書き込み、または ON CLUSTER 経由) で挿入された行は、この境界の対象外であり、欠落または重複する可能性があります。
データ投入が失敗した場合 (たとえば、負荷の高いソーステーブルに対する排他ロックを lock_acquire_timeout 内に取得できない場合や、実行中に VIEW の SELECT が例外を発生させた場合) 、作成直後の VIEW は削除され、CREATE クエリは失敗します。作成されたものは何も残らないため、単純に再試行できます。TO [db].[table] 形式では、このロールバックで削除されるのは VIEW のみであり、既存のターゲットテーブルが削除されることはありません。ただし、失敗したデータ投入ですでにターゲットに挿入された行は、当該テーブルへの INSERT ... SELECT が失敗した後と同様に残るため、CREATE を再試行すると再度挿入されます。バックフィルを正確に行う必要がある場合は、切り詰めたターゲットテーブルまたは新しいターゲットテーブルに再試行するか、ReplacingMergeTree のような重複排除エンジンを使用してください。
アトミック性を確保するには、ソーステーブルが固定された特定時点のスナップショットの読み取りをサポートしている必要があります。対象は
MergeTree ファミリーと Memory です。それ以外のソース (VIEW、Distributed、Merge、Buffer、Log ファミリー、または Atomic database に含まれない table) では、データ投入は従来の非アトミックな動作にフォールバックします (server log に記録されます) 。既存データは個別の非協調スナップショットで読み取られるため、データ投入中に挿入された行が欠落または重複する可能性があります。その場合、正確なデータが必要であれば VIEW を作成し、個別に INSERT ... SELECT を実行してください。materialized_views_populate_atomically = 0 を設定すると、すべてのソースでこの従来の動作が強制されます。アトミックなデータ投入は、通常の CREATE MATERIALIZED VIEW にのみ適用されます。CREATE OR REPLACE / REPLACE MATERIALIZED VIEW ... POPULATE は常に従来の非アトミックなデータ投入を使用します。POPULATE は Replicated databases ではサポートされていません (database_replicated_allow_heavy_create を使用すると上書きできます) 。また、ClickHouse Cloud でもサポートされていません。この上書きによって有効にした場合、データ投入は常に従来の非アトミックなものになります。失敗したデータ投入をすべてのレプリカで一貫してロールバックすることはできないためです。SELECT クエリには DISTINCT、GROUP BY、ORDER BY、LIMIT を含めることができます。対応する変換は、挿入されるデータの各ブロックごとに独立して実行される点に注意してください。たとえば、GROUP BY が設定されている場合、データは挿入時に集約されますが、それは挿入データの単一のパケット内でのみ行われます。データがその後さらに集約されることはありません。例外は、SummingMergeTree のように、データ集約を独自に実行する ENGINE を使用する場合です。
materialized VIEW が TO [db.]name 構文を使用している場合は、その VIEW を DETACH し、ターゲットテーブルに対して ALTER を実行したあとで、先ほどデタッチした (DETACH) VIEW を ATTACH できます。
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 NONE は非推奨のオプションです。SQL SECURITY NONE を指定してビューを作成する権限を持つユーザーは、任意のクエリを実行できてしまいます。
そのため、このオプションでビューを作成するには GRANT ALLOW SQL SECURITY NONE TO <user> が必要です。DEFINER/SQL SECURITY が指定されていない場合、結果は ignore_empty_sql_security_in_create_view_query サーバー設定によって異なります。
デフォルト値の true では、クエリは記述どおりに保存され、ビューには空の SQL security タイプが設定されます。通常のビューは呼び出し元の権限で実行され、ターゲットテーブルが明示的に指定された materialized view では、そのターゲットテーブルに対するアクセスチェックがスキップされます。つまり、ソーステーブルへの挿入にはターゲットテーブルに対する INSERT 権限は不要であり、ビューからの読み取りにはそのターゲットテーブルに対する SELECT 権限は不要です。
false では、作成時に次のデフォルト値がビュー定義に書き込まれます。
SQL SECURITY: 通常のビューではINVOKER(default_normal_view_sql_securityで設定可能) 、materialized view ではDEFINER(default_materialized_view_sql_securityで設定可能)DEFINER:CURRENT_USER(default_view_definerで設定可能)
DEFINER/SQL SECURITY なしで保存されたビューは、空の SQL security タイプを維持します。
既存のビューの 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 ... の省略形です。詳細は以下の リフレッシュの依存関係 を参照してください。
対応するクエリを定期的に実行し、その結果をテーブルに格納します。
APPENDが指定されている場合、各リフレッシュでは既存の行を削除せずにテーブルへ行を挿入します。この insert は、通常のINSERT INTO ... SELECTクエリと同様にアトミックではありません。APPEND INCREMENTALが指定されている場合、各リフレッシュでは前回のリフレッシュ以降にソーステーブルへコミットされた行のみを対象にクエリを実行し、その結果を追加します。- それ以外の場合、各リフレッシュでテーブルの以前の内容はアトミックに置き換えられます。
- insert trigger はありません。
SELECTで指定したテーブルに新しいデータが挿入されても、そのデータがリフレッシャブルmaterialized view に自動的に反映されることは ありません。代わりに、データの挿入は定期実行または手動実行のリフレッシュ時にのみ行われます。 SELECTクエリには制約がありません。テーブル関数 (例:url()) 、ビュー、UNION、JOIN はいずれも使用できます。唯一の例外はAPPEND INCREMENTALで、enable_block_number_column = 1およびenable_block_offset_column = 1を設定した単一のプレーンなMergeTreeソーステーブルが必要であり、JOIN、UNION、サブクエリ、ビュー、テーブル関数は使用できません。
クエリの
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 内で
リフレッシャブルmaterialized view が Replicated database 内にある場合、各レプリカは相互に協調し、スケジュールされた時刻ごとに 1 つのレプリカだけがリフレッシュを実行します。リフレッシュで生成されたデータをすべてのレプリカが参照できるようにするため、ReplicatedMergeTree テーブルエンジンが必要です。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。
リフレッシュパラメータの変更
既存のリフレッシャブルmaterialized viewのリフレッシュパラメータは、ALTER TABLE ... MODIFY REFRESHを使って変更します。
EVERY または AFTER) の指定は必須です。このステートメントでは、リフレッシュに関するすべてのパラメーター (スケジュール、RANDOMIZE FOR、DEPENDS ON、およびリフレッシュ設定) が、指定した内容で常に丸ごと置き換えられます。省略した項目は、設定であればデフォルト値に戻され、依存関係やランダム化であれば削除されます。
-
リフレッシュ設定のみを変更するには (例:
refresh_retries) 、現在のスケジュールを再度指定してください。 -
ALTER TABLE ... MODIFY SETTING refresh_retries = ...は materialized view ではサポートされていません。必ずMODIFY REFRESHを使用してください。 -
リフレッシュモードの変更はサポートされていません。
APPENDとINCREMENTALは追加も削除もできません。 -
all_replicas設定は作成後に変更できません。
その他の操作
すべてのリフレッシャブルmaterialized viewの状態は、テーブルsystem.view_refreshesで確認できます。特に、リフレッシュの進行状況 (実行中の場合) 、前回および次回のリフレッシュ時刻、リフレッシュが失敗した場合の例外メッセージが含まれます。
手動でリフレッシュを停止、開始、トリガー、またはキャンセルするには、SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEWを使用します。
リフレッシュの完了を待機するには、SYSTEM WAIT VIEWを使用します。特に、ビューの作成後に初回リフレッシュが完了するのを待つ際に便利です。
豆知識: リフレッシュクエリは、現在リフレッシュ中のビューから読み取ることができ、その際にはリフレッシュ前のバージョンのデータを参照します。つまり、Conway’s Game of Life を実装できます: https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==
関連コンテンツ
一時ビュー
ClickHouse は、一時ビューをサポートしており、次のような特性があります (該当する場合は一時テーブルと同様です) 。- セッション存続期間 一時ビューは現在のセッション中にのみ存在します。セッションが終了すると自動的に削除されます。
- データベースなし 一時ビューをデータベース名で修飾することはできません。一時ビューはデータベースの外側 (セッションのネームスペース) に存在します。
-
レプリケートされない / 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 ...→ 使用できません。CREATE TEMPORARY VIEW db.view AS ...→ 使用できません (データベース修飾子は指定できません) 。CREATE TEMPORARY VIEW view ON CLUSTER 'name' AS ...→ 使用できません (一時オブジェクトはセッションローカルです) 。POPULATE,REFRESH,TO [db.table], 内部エンジン、および MV 固有の句は、一時ビューには 適用されません。
分散クエリに関する注意事項
一時ビューは単なる定義にすぎず、受け渡すデータはありません。一時ビューが一時テーブル (たとえばMemory) を参照している場合、そのデータは一時テーブルと同様に、分散クエリの実行中にリモートサーバーへ転送されることがあります。