メインコンテンツへスキップ
メインコンテンツへスキップ

CREATE VIEW

新しいビューを作成します。ビューには通常ビューマテリアライズドビューリフレッシュ可能なマテリアライズドビュー、およびウィンドウビューの種類があります。

標準表示

構文:

CREATE [OR REPLACE] VIEW [IF NOT EXISTS] [db.]table_name [(alias1 [, alias2 ...])] [ON CLUSTER cluster_name]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | INVOKER | NONE }]
AS SELECT ...
[COMMENT 'comment']

通常のビューはデータを一切保存しません。アクセスのたびに別のテーブルからの読み取りを実行するだけです。言い換えると、通常のビューは保存されたクエリに過ぎません。ビューから読み取る場合、この保存されたクエリは FROM 句内のサブクエリとして使用されます。

例として、ビューを作成したとします。

CREATE VIEW view AS SELECT ...

また、次のクエリを作成しました:

SELECT a, b, c FROM view

このクエリは、サブクエリを使用したものと完全に同等です。

SELECT a, b, c FROM (SELECT ...)

パラメータ化ビュー

パラメータ化ビューは通常のビューと似ていますが、ただちには解決されないパラメータを指定して作成できます。これらのビューはテーブル関数で使用でき、その際はビュー名を関数名として指定し、パラメータ値をその引数として渡します。

CREATE VIEW view AS SELECT * FROM TABLE WHERE Column1={column1:datatype1} and Column2={column2:datatype2} ...

上記によりテーブルに対するビューが作成され、以下のようにパラメータを指定することでテーブル関数として利用できます。

SELECT * FROM view(column1=value1, column2=value2 ...)

マテリアライズドビュー

CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster_name] [TO[db.]name [(columns)]] [ENGINE = engine] [POPULATE]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'コメント']
ヒント

マテリアライズドビューのステップバイステップガイドがあります。

マテリアライズドビューは、対応するSELECT クエリによって変換されたデータを保存します。

TO [db].[table] を指定せずにマテリアライズドビューを作成する場合は、データを保存するテーブルエンジンである ENGINE を指定する必要があります。

TO [db].[table] を指定してマテリアライズドビューを作成する場合、POPULATE を同時に使用することはできません。

マテリアライズドビューは次のように実装されています。SELECT で指定されたテーブルにデータを挿入すると、その挿入データの一部がこの SELECT クエリによって変換され、その結果がビューに挿入されます。

注記

ClickHouse のマテリアライズドビューでは、デスティネーションテーブルへの挿入時に、列の並び順ではなく列名が使用されます。SELECT クエリ結果に一部の列名が存在しない場合、たとえその列が Nullable でなくても、ClickHouse はその列にデフォルト値を使用します。安全な方法としては、マテリアライズドビューを使用する際に、すべての列に対してエイリアスを追加することが推奨されます。

ClickHouse のマテリアライズドビューは、挿入トリガーに近い仕組みで実装されています。ビューのクエリに集約が含まれている場合、その集約は新たに挿入されたバッチデータに対してのみ適用されます。ソーステーブルの既存データに対する変更(update、delete、パーティションの drop など)は、マテリアライズドビューを変更しません。

ClickHouse のマテリアライズドビューは、エラー発生時の動作が決定的ではありません。つまり、すでに書き込まれたブロックはデスティネーションテーブルに保持されますが、エラー以降のブロックは書き込まれません。

デフォルトでは、いずれかのビューへのプッシュが失敗すると、INSERT クエリ自体も失敗し、一部のブロックがデスティネーションテーブルに書き込まれない可能性があります。これは materialized_views_ignore_errors 設定(INSERT クエリに対して設定する必要があります)を使用して変更できます。materialized_views_ignore_errors=true を設定すると、ビューへのプッシュ中のエラーはすべて無視され、すべてのブロックがデスティネーションテーブルに書き込まれます。

なお、materialized_views_ignore_errorssystem.*_log テーブルに対してはデフォルトで true に設定されています。

POPULATE を指定すると、CREATE TABLE ... AS SELECT ... を実行したかのように、既存のテーブルデータがビュー作成時にビューへ挿入されます。指定しない場合、ビューにはビュー作成後にテーブルに挿入されたデータのみが含まれます。ビュー作成中にテーブルへ挿入されたデータはビューへ挿入されないため、POPULATE を使用することは推奨しません

注記

POPULATECREATE TABLE ... AS SELECT ... のように動作するため、次の制約があります。

  • Replicated database ではサポートされません
  • ClickHouse Cloud ではサポートされません

代わりに、別途 INSERT ... SELECT を使用できます。

SELECT クエリには DISTINCTGROUP BYORDER BYLIMIT を含めることができます。対応する変換は、挿入されたデータの各ブロックごとに独立して実行される点に注意してください。たとえば、GROUP BY が設定されている場合、データは挿入時に集約されますが、単一の挿入パケット内だけで集約されます。その後にさらに集約が行われることはありません。例外として、SummingMergeTree のように独立してデータ集約を実行する ENGINE を使用する場合があります。

マテリアライズドビューに対する ALTER クエリの実行には制限があり、例えば SELECT クエリを更新することはできないため、不便な場合があります。マテリアライズドビューが TO [db.]name 構文を使用している場合は、ビューを DETACH し、対象テーブルに対して ALTER を実行し、その後で先ほど DETACH したビューを ATTACH できます。

マテリアライズドビューは、optimize_on_insert 設定の影響を受ける点に注意してください。ビューへの挿入前にデータがマージされます。

ビューは通常のテーブルと同様に扱われます。たとえば、SHOW TABLES クエリの結果にも表示されます。

ビューを削除するには、DROP VIEW を使用します。DROP TABLE も VIEW に対して動作します。

SQL セキュリティ

DEFINERSQL SECURITY を使用すると、ビューの背後で実行されるクエリを実行する際に、どの ClickHouse ユーザーを使用するかを指定できます。 SQL SECURITY には DEFINERINVOKERNONE の 3 つの有効な値があります。DEFINER 句では、既存の任意のユーザー、または CURRENT_USER を指定できます。

次の表では、ビューから SELECT するために、どのユーザーにどの権限が必要かを示します。 なお、SQL セキュリティオプションに関係なく、どの場合でもビューを読み取るには GRANT SELECT ON <view> が必要です。

SQL security optionViewMaterialized View
DEFINER alicealice はビューのソーステーブルに対する SELECT 権限を持っている必要があります。alice はビューのソーステーブルに対する SELECT 権限と、ビューのターゲットテーブルに対する INSERT 権限を持っている必要があります。
INVOKERユーザーはビューのソーステーブルに対する SELECT 権限を持っている必要があります。マテリアライズドビューでは SQL SECURITY INVOKER を指定できません。
NONE--
注記

SQL SECURITY NONE は非推奨のオプションです。SQL SECURITY NONE でビューを作成する権限を持つ任意のユーザーは、任意のクエリを実行できてしまいます。 したがって、このオプションを使用してビューを作成するには、GRANT ALLOW SQL SECURITY NONE TO <user> が必要です。

DEFINER / SQL SECURITY が指定されていない場合、デフォルト値が使用されます:

DEFINER / SQL SECURITY を指定せずにビューがアタッチされた場合、マテリアライズドビューではデフォルト値は SQL SECURITY NONE、通常のビューでは SQL SECURITY INVOKER になります。

既存のビューの SQL セキュリティを変更するには、次を使用します

ALTER TABLE MODIFY SQL SECURITY { DEFINER | INVOKER | NONE } [DEFINER = { user | CURRENT_USER }]

使用例

CREATE VIEW test_view
DEFINER = alice SQL SECURITY DEFINER
AS SELECT ...
CREATE VIEW test_view
SQL SECURITY INVOKER
AS SELECT ...

ライブビュー

Deprecated feature

この機能は非推奨となっており、将来削除される予定です。

参考までに、旧ドキュメントはこちらにあります。

リフレッシュ可能なマテリアライズドビュー

CREATE MATERIALIZED VIEW [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
REFRESH EVERY|AFTER interval [OFFSET interval]
[RANDOMIZE FOR interval]
[DEPENDS ON [db.]name [, [db.]name [, ...]]]
[SETTINGS name = value [, name = value [, ...]]]
[APPEND]
[TO[db.]name] [(columns)] [ENGINE = engine]
[EMPTY]
[DEFINER = { user | CURRENT_USER }] [SQL SECURITY { DEFINER | NONE }]
AS SELECT ...
[COMMENT 'コメント']

ここで、interval は一連の単純なインターバルです。

number 秒|分|時間|日|週|月|年

対応するクエリを定期的に実行し、その結果をテーブルに保存します。

  • クエリに APPEND が指定されている場合、各リフレッシュで既存の行を削除せずにテーブルに行を挿入します。挿入は通常の INSERT SELECT と同様にアトミックではありません。
  • それ以外の場合、各リフレッシュでテーブルの以前の内容をアトミックに置き換えます。

通常の(リフレッシュ非対応の)マテリアライズドビューとの違い:

  • 挿入トリガーはありません。つまり、SELECT で指定されたテーブルに新しいデータが挿入されても、それが自動的にリフレッシュ可能なマテリアライズドビューに反映されることは ありません。定期的なリフレッシュ時に、クエリ全体が実行されます。
  • SELECT クエリに制限はありません。テーブル関数(例: url())、ビュー、UNION、JOIN などがすべて利用可能です。
注記

クエリ中の REFRESH ... SETTINGS 部分にある設定はリフレッシュに関する設定(例: refresh_retries)であり、通常の設定(例: max_threads)とは異なります。通常の設定はクエリ末尾の SETTINGS で指定できます。

リフレッシュスケジュール

リフレッシュスケジュールの例:

REFRESH EVERY 1 DAY -- 毎日、UTC の午前0時に
REFRESH EVERY 1 MONTH -- 毎月1日の午前0時に
REFRESH EVERY 1 MONTH OFFSET 5 DAY 2 HOUR -- 毎月6日の午前2時に
REFRESH EVERY 2 WEEK OFFSET 5 DAY 15 HOUR 10 MINUTE -- 隔週の土曜日の午後3時10分に
REFRESH EVERY 30 MINUTE -- 00:00、00:30、01:00、01:30 などの時刻に
REFRESH AFTER 30 MINUTE -- 前回のリフレッシュ完了から30分後。特定の時刻には揃えない。
-- REFRESH AFTER 1 HOUR OFFSET 1 MINUTE -- 構文エラー。AFTER と組み合わせて OFFSET は使用できない。
REFRESH EVERY 1 WEEK 2 DAYS -- 9日ごとで、特定の曜日や月の日付には紐づかない;
                            -- 具体的には、(1969-12-29 からの)日数が 9 で割り切れる場合
REFRESH EVERY 5 MONTHS -- 5か月ごと。12 は 5 で割り切れないため、毎年異なる月になる;
                       -- 具体的には、(1970-01 からの)月数が 5 で割り切れる場合

RANDOMIZE FOR は各リフレッシュのタイミングをランダムに調整します。例:

REFRESH EVERY 1 DAY OFFSET 2 HOUR RANDOMIZE FOR 1 HOUR -- 毎日、01:30 から 02:30 の間のランダムな時刻にリフレッシュ

特定のビューについて、同時に実行できるリフレッシュは最大でも 1 つだけです。たとえば、REFRESH EVERY 1 MINUTE を指定したビューのリフレッシュに 2 分かかる場合、実際には 2 分ごとにリフレッシュされることになります。その後、処理が高速化されて 10 秒でリフレッシュできるようになった場合は、再び 1 分ごとのリフレッシュに戻ります。(特に、スケジュールどおりに行えなかったリフレッシュを取り戻すために 10 秒ごとにリフレッシュされることはなく、そのようなバックログの概念もありません。)

さらに、CREATE クエリで EMPTY が指定されていない限り、マテリアライズドビューが作成されると直ちにリフレッシュが開始されます。EMPTY が指定されている場合、最初のリフレッシュはスケジュールに従って行われます。

Replicated DB において

リフレッシュ可能なマテリアライズドビューが Replicated database 内にある場合、各レプリカは互いに調整し、各スケジュールされた時刻には 1 つのレプリカだけがリフレッシュを実行するようにします。ReplicatedMergeTree テーブルエンジンが必須であり、これによりすべてのレプリカがリフレッシュによって生成されたデータを参照できます。

APPEND モードでは、SETTINGS all_replicas = 1 を使用して調整を無効化できます。これにより、レプリカは互いに独立してリフレッシュを実行します。この場合、ReplicatedMergeTree は必須ではありません。

APPEND モードでは、協調リフレッシュのみがサポートされます。非協調なリフレッシュを行いたい場合は、Atomic データベースと CREATE ... ON CLUSTER クエリを使用して、すべてのレプリカ上にリフレッシュ可能なマテリアライズドビューを作成します。

協調処理は Keeper を通じて行われます。znode のパスは、default_replica_path サーバー設定によって決定されます。

依存関係

DEPENDS ON は、異なるテーブルのリフレッシュを同期します。例として、2 つのリフレッシュ可能なマテリアライズドビューが連なったチェーン構造になっているとします。

CREATE MATERIALIZED VIEW source REFRESH EVERY 1 DAY AS SELECT * FROM url(...)
CREATE MATERIALIZED VIEW destination REFRESH EVERY 1 DAY AS SELECT ... FROM source

DEPENDS ON を指定しない場合、両方のビューは深夜にリフレッシュを開始し、destination には通常、source 内の前日分のデータが見えることになります。依存関係を追加すると、次のようになります:

CREATE MATERIALIZED VIEW destination REFRESH EVERY 1 DAY DEPENDS ON source AS SELECT ... FROM source

この場合、その日の source のリフレッシュが完了してからでないと destination のリフレッシュは開始されないため、destination は最新のデータに基づくことになります。

別の方法として、同じ結果を次のようにしても実現できます。

CREATE MATERIALIZED VIEW destination REFRESH AFTER 1 HOUR DEPENDS ON source AS SELECT ... FROM source

ここで、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 HOURREFRESH EVERY 1 DAY OFFSET 23 HOUR に依存する場合
    上記と同様ですが、対応するリフレッシュが異なる暦日で発生する点が異なります。 日 X+1 における destination のリフレッシュは、日 X における source のリフレッシュが完了するまで待機します(それに 2 時間以上かかる場合)。
  • REFRESH EVERY 2 HOURREFRESH EVERY 1 HOUR に依存する場合
    2 HOUR のリフレッシュは、1 時間おきに 1 HOUR のリフレッシュの後で実行されます。例えば、真夜中の リフレッシュの後、その次は午前 2 時のリフレッシュの後、というように続きます。
  • REFRESH EVERY 1 MINUTEREFRESH EVERY 2 HOUR に依存する場合
    REFRESH AFTER 1 MINUTEREFRESH EVERY 2 HOUR に依存する場合
    REFRESH AFTER 1 MINUTEREFRESH AFTER 2 HOUR に依存する場合
    destination は、すべての source のリフレッシュごとに 1 回リフレッシュされます。つまり 2 時間ごとです。1 MINUTE は実質的に無視されます。
  • REFRESH AFTER 1 HOURREFRESH AFTER 1 HOUR に依存する場合
    現在、これは推奨されません。
注記

DEPENDS ON は、リフレッシュ可能なマテリアライズドビュー同士でのみ機能します。DEPENDS ON のリストに通常のテーブルを指定すると、そのビューは一度もリフレッシュされなくなります(依存関係は ALTER で削除できます。後述を参照してください)。

設定

利用可能なリフレッシュ設定:

  • refresh_retries - リフレッシュクエリが例外で失敗した場合に再試行する回数。すべての再試行が失敗した場合、次のスケジュールされたリフレッシュ時刻までスキップします。0 は再試行なし、-1 は無制限に再試行することを意味します。デフォルト: 0。
  • refresh_retry_initial_backoff_ms - refresh_retries が 0 でない場合の、最初の再試行までの遅延。以降の再試行ごとに、この遅延は 2 倍になり、refresh_retry_max_backoff_ms まで増加します。デフォルト: 100 ms。
  • refresh_retry_max_backoff_ms - リフレッシュ試行間の遅延の指数的な増加に対する上限。デフォルト: 60000 ms(1 分)。

リフレッシュパラメータの変更

リフレッシュパラメータを変更するには:

ALTER TABLE [db.]name MODIFY REFRESH EVERY|AFTER ... [RANDOMIZE FOR ...] [DEPENDS ON ...] [SETTINGS ...]
注記

これは、スケジュール、依存関係、設定、および APPEND モードかどうかを含む すべて のリフレッシュパラメータを一括で置き換えます。たとえば、テーブルに DEPENDS ON がある状態で、DEPENDS ON を指定せずに MODIFY REFRESH を実行すると、依存関係は削除されます。

その他の操作

すべてのリフレッシュ可能なマテリアライズドビューのステータスは、テーブル system.view_refreshes で確認できます。特に、(実行中であれば)リフレッシュの進捗状況、直近および次回のリフレッシュ時刻、リフレッシュが失敗した場合の例外メッセージが含まれます。

リフレッシュを手動で停止、開始、トリガー、キャンセルするには、SYSTEM STOP|START|REFRESH|WAIT|CANCEL VIEW を使用します。

リフレッシュが完了するまで待機するには、SYSTEM WAIT VIEW を使用します。特に、ビュー作成後の初回リフレッシュ完了を待つ場合に有用です。

注記

豆知識: リフレッシュクエリは、リフレッシュ対象のビューから読み取ることができ、その場合はリフレッシュ前のバージョンのデータが見えます。これは、Conway's Game of Life(ライフゲーム)を実装できることを意味します: https://pastila.nl/?00021a4b/d6156ff819c83d490ad2dcec05676865#O0LGWTO7maUQIA4AcGUtlA==

ウィンドウビュー

Experimental feature. Learn more.
Not supported in ClickHouse Cloud
参考文献

これは実験的な機能であり、将来のリリースで後方互換性のない形で変更される可能性があります。ウィンドウビューおよび WATCH クエリを使用するには、allow_experimental_window_view 設定を有効にしてください。set allow_experimental_window_view = 1 コマンドを実行します。

CREATE WINDOW VIEW [IF NOT EXISTS] [db.]table_name [TO [db.]table_name] [INNER ENGINE engine] [ENGINE engine] [WATERMARK strategy] [ALLOWED_LATENESS interval_function] [POPULATE]
AS SELECT ...
GROUP BY time_window_function
[COMMENT 'コメント']

Window view は、時間ウィンドウごとにデータを集約し、ウィンドウがトリガーされる準備が整った時点で結果を出力できます。レイテンシーを下げるために、中間の集約結果を内部(または指定された)テーブルに保存し、処理結果を指定したテーブルにプッシュしたり、WATCH クエリを使用して通知をプッシュしたりできます。

Window view の作成方法は MATERIALIZED VIEW の作成と似ています。Window view では、中間データを保存するための内部ストレージエンジンが必要です。INNER ENGINE 句を使用して内部ストレージを指定でき、指定がない場合は AggregatingMergeTree がデフォルトの内部エンジンとして使用されます。

TO [db].[table] を指定せずに window view を作成する場合は、データを保存するテーブルエンジンとして ENGINE を必ず指定する必要があります。

Time Window Functions

Time window functions は、レコードに対するウィンドウの下限と上限を取得するために使用されます。Window view は time window function と併用する必要があります。

TIME ATTRIBUTES

Window view は processing timeevent time の 2 種類の処理に対応しています。

Processing time は、ローカルマシンの時刻に基づいて window view が結果を生成できるようにするもので、デフォルトで使用されます。最も単純な時間の概念ですが、決定的な結果を保証するものではありません。Processing time 属性は、time window function の time_attr をテーブル列に設定するか、関数 now() を使用することで定義できます。次のクエリは、processing time を用いた window view を作成します。

ウィンドウ VIEW wv を作成 AS SELECT count(number), tumbleStart(w_id) を w_start として date から取得 GROUP BY tumble(now(), INTERVAL '5' SECOND) を w_id として

イベント時刻 (event time) は、各イベントが生成元デバイス上で実際に発生した時刻です。この時刻は通常、レコードが生成される際にそのレコード内に埋め込まれます。イベント時刻に基づいて処理を行うことで、順序が前後したイベントや遅延して到着するイベントが存在する場合でも、一貫した結果を得ることができます。Window View は WATERMARK 構文を使用することで、イベント時刻処理をサポートします。

Window View では、次の 3 種類のウォーターマーク戦略を提供します。

  • STRICTLY_ASCENDING: これまでに観測された最大のタイムスタンプをウォーターマークとして出力します。タイムスタンプがこの最大値より小さい行は、遅延したとはみなされません。
  • ASCENDING: これまでに観測された最大のタイムスタンプから 1 を引いた値をウォーターマークとして出力します。タイムスタンプがこの最大値以下の行は、遅延したとはみなされません。
  • BOUNDED: WATERMARK=INTERVAL。指定された遅延時間を、これまでに観測された最大のタイムスタンプから差し引いた値をウォーターマークとして出力します。

次のクエリは、WATERMARK を使用して Window View を作成する例です。

CREATE WINDOW VIEW wv WATERMARK=STRICTLY_ASCENDING AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
CREATE WINDOW VIEW wv WATERMARK=ASCENDING AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);
CREATE WINDOW VIEW wv WATERMARK=INTERVAL '3' SECOND AS SELECT count(number) FROM date GROUP BY tumble(timestamp, INTERVAL '5' SECOND);

デフォルトでは、ウィンドウはウォーターマークが到達したときにトリガーされ、ウォーターマーク以降に到着した要素は破棄されます。Window view は、ALLOWED_LATENESS=INTERVAL を設定することで遅延イベントの処理をサポートします。遅延イベント処理の例は次のとおりです。

CREATE WINDOW VIEW test.wv TO test.dst WATERMARK=ASCENDING ALLOWED_LATENESS=INTERVAL '2' SECOND AS SELECT count(a) AS count, tumbleEnd(wid) AS w_end FROM test.mt GROUP BY tumble(timestamp, INTERVAL '5' SECOND) AS wid;

遅延して発火した際に出力される要素は、以前の計算結果が更新されたものとして扱う必要があります。ウィンドウの終了時に発火するのではなく、ウィンドウビューは遅延イベントが到着したタイミングで即座に発火します。そのため、同じウィンドウに対して複数の出力が生成されます。ユーザーはこれらの重複した結果を考慮に入れるか、重複排除する必要があります。

ALTER TABLE ... MODIFY QUERY ステートメントを使用して、ウィンドウビューで指定されている SELECT クエリを変更できます。新しい SELECT クエリで得られるデータ構造は、TO [db.]name 句の有無にかかわらず、元の SELECT クエリと同一である必要があります。中間状態は再利用できないため、現在のウィンドウ内のデータは失われることに注意してください。

新しいウィンドウの監視

ウィンドウビューでは、変更を監視するために WATCH クエリを使用するか、TO 構文を用いて結果をテーブルに出力できます。

WATCH [db.]window_view
[EVENTS]
[LIMIT n]
[FORMAT format]

LIMIT を指定すると、クエリを終了するまでに受信する更新の回数を制限できます。EVENTS 句を使用すると、クエリ結果そのものではなく最新のクエリウォーターマークのみを取得する、WATCH クエリの簡略な形式を利用できます。

設定

  • window_view_clean_interval: 古いデータを解放するための、ウィンドウビューのクリーン処理の間隔(秒)です。システムは、システム時刻または WATERMARK の設定に従ってまだ完全にはトリガーされていないウィンドウを保持し、それ以外のデータを削除します。
  • window_view_heartbeat_interval: WATCH クエリが稼働中であることを示すためのハートビート間隔(秒)です。
  • wait_for_window_view_fire_signal_timeout: イベント時間処理において、ウィンドウビューの発火シグナルを待機する際のタイムアウトです。

data というログテーブルで 10 秒ごとのクリックログの件数を集計する必要があるとし、そのテーブル構造は次のようになっているとします。

CREATE TABLE data ( `id` UInt64, `timestamp` DateTime) ENGINE = Memory;

まず、10 秒間隔のタンブリングウィンドウを持つウィンドウビューを作成します。

CREATE WINDOW VIEW wv as select count(id), tumbleStart(w_id) as window_start from data group by tumble(timestamp, INTERVAL '10' SECOND) as w_id

次に、結果を取得するために WATCH クエリを使用します。

WATCH wv

ログがdataテーブルに挿入されると、

INSERT INTO data VALUES(1,now())

WATCH クエリは、次のように結果を表示します。

┌─count(id)─┬────────window_start─┐
│         1 │ 2020-01-14 16:56:40 │
└───────────┴─────────────────────┘

別の方法として、TO 構文を使用して、出力先として別のテーブルを指定することもできます。

CREATE WINDOW VIEW wv TO dst AS SELECT count(id), tumbleStart(w_id) as window_start FROM data GROUP BY tumble(timestamp, INTERVAL '10' SECOND) as w_id

追加の例は、ClickHouse の stateful テストの中にあります(そこでの名前は *window_view* です)。

Window View の使用方法

Window View は次のようなシナリオで有用です。

  • Monitoring: メトリクスログを時間単位で集計・計算し、その結果をターゲットテーブルに出力します。ダッシュボードはターゲットテーブルをソーステーブルとして利用できます。
  • Analyzing: 時間ウィンドウ内のデータを自動的に集計および前処理します。これは大量のログを分析する際に有用です。前処理によって複数のクエリにおける繰り返し計算が不要になり、クエリのレイテンシを低減できます。

一時ビュー

ClickHouse は、以下の特徴を持つ 一時ビュー (temporary 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; を使用します。

構文

一時ビューを作成 [IF NOT EXISTS] view_name AS <select_query>

OR REPLACE は一時テーブルとの整合性を保つため、一時ビューではサポートされていません。一時ビューを「置き換える」必要がある場合は、削除してから再作成してください。

一時ソーステーブルと、その上に一時ビューを作成します:

CREATE TEMPORARY TABLE t_src (id UInt32, val String);
INSERT INTO t_src VALUES (1, 'a'), (2, 'b');

CREATE TEMPORARY VIEW tview AS
SELECT id, upper(val) AS u
FROM t_src
WHERE id <= 2;

SELECT * FROM tview ORDER BY id;

DDL を表示します:

一時ビュー tview の作成文を表示;

削除するには:

DROP TEMPORARY VIEW IF EXISTS tview;  -- 一時ビューは TEMPORARY TABLE 構文を使って削除されます

禁止事項 / 制限事項

  • 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 ...使用不可(一時オブジェクトはセッションローカルなものです)。
  • POPULATEREFRESHTO [db.table]、内部エンジン、およびすべての MV 固有の句 → 一時ビューには 適用されません

分散クエリに関する注意事項

一時 ビュー は単なる定義であり、転送されるデータ自体は存在しません。一時ビューが一時 テーブル(例: Memory)を参照している場合、そのデータは分散クエリの実行時に、一時テーブルと同様の方法でリモートサーバーに送信されます。

-- セッション単位のインメモリテーブル
CREATE TEMPORARY TABLE temp_ids (id UInt64) ENGINE = Memory;

INSERT INTO temp_ids VALUES (1), (5), (42);

-- 一時テーブルに対するセッション単位のビュー(純粋に論理的なオブジェクト)
CREATE TEMPORARY VIEW v_ids AS
SELECT id FROM temp_ids;

-- 'test' をクラスタ名に置き換えてください。
-- GLOBAL JOIN により、ClickHouse は小さい結合側(v_ids を介した temp_ids)を
-- 左側を実行するすべてのリモートサーバーへ送信するよう強制されます。
SELECT count()
FROM cluster('test', system.numbers) AS n
GLOBAL ANY INNER JOIN v_ids USING (id)
WHERE n.number < 100;