動的テーブルリフレッシュについて

動的テーブルのコンテンツは、特定のクエリの結果に基づいています。動的テーブルの基となるデータが変更されると、その変更を反映してテーブルが更新されます。これらの更新は リフレッシュ と呼ばれます。このプロセスは自動化されており、テーブルの基礎となるクエリを分析します。

動的テーブルリフレッシュのタイムアウトは STATEMENT_TIMEOUT_IN_SECONDS パラメーターによって決定され、アカウントまたはウェアハウスが自動的にキャンセルされるまでの最大期間を定義します。

以下のセクションでは、動的テーブルリフレッシュについて詳しく説明します。

動的テーブルのリフレッシュモード

動的テーブルリフレッシュプロセスは、次の2つの方法のいずれかで動作します。

  1. 増分リフレッシュ: この自動化されたプロセスでは、動的テーブルのクエリを分析し、前回のリフレッシュからの変更点を計算します。そして、これらの変更をテーブルにマージします。サポートされるクエリの詳細については、 増分リフレッシュでサポートされるクエリ をご参照ください。

  2. フルリフレッシュ: 自動プロセスが増分リフレッシュを実行できない場合、フルリフレッシュを実行します。これには、動的テーブルのクエリを実行し、以前の具体化された結果を完全に置き換えることが含まれます。

クエリで使用されるコンストラクトは、増分リフレッシュが使用できるかどうかを決定します。動的テーブルを作成した後、 テーブルをモニター して、そのテーブルのリフレッシュに増分リフレッシュまたはフルリフレッシュが使用されているかどうかを判断することができます。

ターゲットラグについて

動的テーブルのリフレッシュは、データの古さの度合い、または ターゲットラグ と一般的に呼ばれるものに基づいてトリガーされます。動的テーブルのターゲットラグは、直接上流の動的テーブルではなく、グラフのルートのベーステーブルを基準として測定されます。Snowflakeは、動的テーブルの実際のラグをターゲットラグ以下に保つようにリフレッシュをスケジュールします。各リフレッシュの所要時間は、クエリ、データパターン、ウェアハウスサイズによって異なります。ターゲットラグを選択する際には、ルートへ チェーンの動的テーブル をそれぞれリフレッシュするのに必要な時間を考慮してください。そうしないと、一部のリフレッシュがスキップされ、実際のラグが大きくなる可能性があります。

動的テーブルに接続されているテーブルのグラフを見るには、 Snowsightを使用した動的テーブルグラフの調査 をご参照ください。

ターゲットラグは2つの方法のいずれかで指定します。

  1. 鮮度の測定: テーブルのコンテンツがベーステーブルの更新から遅れる最大時間を定義します。

    次の例では、 product 動的テーブルを1時間ごとにリフレッシュし、鮮度を保つように設定しています。

    ALTER DYNAMIC TABLE product SET TARGET_LAG = '1 hour';
    
    Copy
  2. 下流:他の依存する動的テーブルがリフレッシュされる時に、その動的テーブルがオンデマンドでリフレッシュされるように指定します。このリフレッシュは、下流動的テーブルの手動またはスケジュールされたリフレッシュによってトリガーされます。

    以下の例では、 product は他の動的テーブルに基づいており、その下流動的テーブルのターゲットラグに基づいてリフレッシュするように設定されています。

    ALTER DYNAMIC TABLE product SET TARGET_LAG = DOWNSTREAM;
    
    Copy

ターゲットラグは、動的テーブルのリフレッシュ頻度に反比例します。

動的テーブル1(DT1)に基づいて動的テーブル2(DT2)が定義されている場合を考えてみましょう。DT2は、 DT1 から読み取り、そのコンテンツを具体化する必要があります。さらに、レポートはクエリを介して DT2 データを消費します。

DT1 に基づいて定義された2つの動的テーブル DT2 の簡単な例。

各動的テーブルがラグをどのように指定するかによって、次のような結果が考えられます。

動的テーブル1(DT1)

動的テーブル2(DT2)

リフレッシュの結果

TARGET_LAG = DOWNSTREAM

TARGET_LAG = 10minutes

DT2 は最大10分ごとに更新されます。DT1は、ラグをDT2から推測 し、DT2が更新をリクエストするたびに更新されます。

TARGET_LAG = 10minutes

TARGET_LAG = DOWNSTREAM

このシナリオは避ける必要があります。レポートクエリはデータを受け取りません。DT1は頻繁にリフレッシュされ、DT2はリフレッシュされません。これは、DT2に基づく動的テーブルがないからです。

TARGET_LAG = 5minutes

TARGET_LAG = 10minutes

DT2は、最大5分前のDT1からのデータで約10分ごとに更新されます。

TARGET_LAG = DOWNSTREAM

TARGET_LAG = DOWNSTREAM

DT1 に定義されたラグを持つ下流の子がないため、 DT2 は定期的にはリフレッシュされません。

増分リフレッシュでサポートされるクエリ

次のテーブルでは、現在増分リフレッシュをサポートしている式、キーワード、句について説明します。増分リフレッシュをサポートしないクエリのリストについては、 増分リフレッシュのサポートの制限 をご参照ください。

キーワード/句

増分リフレッシュのサポート

WITH

サブクエリで増分リフレッシュをサポートする機能を使用する 共通テーブル式(CTE)

SELECT 内の式

決定論的組み込み関数や 不変 ユーザー定義関数 を使用した式を含む式。

FROM

ソーステーブル、ビュー、およびその他の動的テーブル。FROM 句外のサブクエリ(例: WHERE EXISTS)はサポートされていません。

OVER

すべての ウィンドウ関数

WHERE/HAVING/QUALIFY

SELECT で有効な式と同じ式のフィルター。

JOIN (およびテーブルを結合するための他の式)

増分リフレッシュでサポートされる結合タイプには、内側結合、外部等価結合、クロス結合、および横方向のフラット化(静的でない FLATTEN テーブル関数のみ)があります。結合するテーブルはいくつでも指定でき、結合内にあるすべてのテーブルの更新はクエリの結果に反映されます。

側方フラット化結合からフラット化 SEQ 列を選択することは、増分リフレッシュではサポートされていません。

UNION ALL

動的テーブルは、 UNION ALL をサポートします。

GROUP BY

動的テーブルは、 GROUP BY をサポートします。

重要

クエリが増分リフレッシュに対応していない式を使用している場合、自動リフレッシュプロセスでは代わりにフルリフレッシュが使用され、追加のコストが発生する可能性があります。どのリフレッシュモードが使用されるかの判断については、 増分リフレッシュまたはフルリフレッシュのいずれが使用されているかの判断 をご参照ください。

増分リフレッシュを使用する動的テーブルで使用中の IMMUTABLE ユーザー定義関数(UDF)を置き換えると、そのテーブルで未定義の動作が発生します。VOLATILE UDFs は増分リフレッシュではサポートされていません。

現在、横方向の結合は増分リフレッシュではサポートされていません。ただし、リフレッシュモードを INCREMENTAL に設定することで、 LATERAL を FLATTEN () と併用することができます。

例:

CREATE TABLE persons
  AS
    SELECT column1 AS id, parse_json(column2) AS entity
    FROM values
      (12712555,
      '{ name:  { first: "John", last: "Smith"},
        contact: [
        { business:[
          { type: "phone", content:"555-1234" },
          { type: "email", content:"j.smith@company.com" } ] } ] }'),
      (98127771,
      '{ name:  { first: "Jane", last: "Doe"},
        contact: [
        { business:[
          { type: "phone", content:"555-1236" },
          { type: "email", content:"j.doe@company.com" } ] } ] }') v;

CREATE DYNAMIC TABLE example
  TARGET_LAG = DOWNSTREAM
  WAREHOUSE = mywh
  REFRESH_MODE = INCREMENTAL
  AS
    SELECT p.id, f.value, f.path
    FROM persons p,
    LATERAL FLATTEN(input => p.entity) f;
Copy

注釈

側方フラット化結合からフラット化 SEQ 列を選択することは、増分リフレッシュではサポートされていません。

演算子が増分リフレッシュする方法

以下のテーブルは、各演算子がどのように増分化されるのか(つまり、完全な結果の代わりに変更を生成する新しいクエリフラグメントに変換されるのか)、そのパフォーマンスとその他の考慮すべき重要な要因の概要を示しています。

演算子

増分

考慮事項

SELECT <スカラー式>

変更された行に式を適用することで増分されます。

パフォーマンスは良好で、特に考慮すべき点はありません。

WHERE <スカラー式>

変更された各行で述語を評価し、述語が真であるものだけを含めることによって増分されます。

パフォーマンスは通常良好です。コストは変更の大きさに応じて直線的に変化します。

非常に選択的なWHERE式で動的テーブルをリフレッシュすると、結果として動的テーブルが変更されなくても、ウェアハウスのアップタイムが必要になることがあります。これは、ソースのどの変更が述語を満たすかを判断するためにウェアハウスが必要になる場合があるためです。

FROM <ベーステーブル>

前回のリフレッシュ以降にテーブルに追加または削除されたマイクロパーティションをスキャンすることで増分されます。

コストは、追加または削除されたマイクロパーティション内のデータ量に比例します。

推奨事項:

  • リフレッシュごとの変更量は、ソーステーブルの約5%に制限します。

  • 多くのマイクロパーティションに影響を与えるDMLsには注意してください。

<クエリ> UNIONALL <クエリ>

各サイドの変更をすべて統合して増分します。

パフォーマンスは良好で、特に考慮すべき点はありません。

WITH <CTEリスト> <クエリ>

各共通表式の変更を計算することによって増分。

WITHは複雑なクエリを読みやすくしますが、1つの動的テーブルの定義を複雑にしすぎないように注意してください。詳細については、 動的テーブルのパイプラインのチェーン および 複雑な動的テーブルに対する増分リフレッシュモードのパフォーマンスの最適化 をご参照ください。

スカラー集計

スカラー集計は現在、効率的に増分されません。入力が変更されると、完全に再計算されます。

GROUPBY <キー>

変更されたグループ化キーごとに集計を再計算することで増分されます。

ソースデータがクラスタリングキーによってクラスタ化され、変更点がグループ化キーのごく一部 (おおよそ<5%) であることを確認します。

グループ化キーがベース列ではなく複合式を含む場合、増分リフレッシュは大量のデータをスキャンしなければならないかもしれません。これらのスキャンのサイズを小さくするために、式を1つの動的テーブルで マテリアライズ し、次に別の動的テーブルでマテリアライズされた列にグループ化操作を適用します。

例えば、次のような複合ステートメントを考えてみましょう:

CREATE DYNAMIC TABLE sums
  AS
    SELECT date_trunc(minute, ts), sum(c1) FROM table
    GROUP BY 1;
Copy

上記のステートメントは次のように最適化できます:

CREATE DYNAMIC TABLE intermediate
  AS
    SELECT date_trunc(minute, ts) ts_min, c1 FROM table;
Copy
CREATE DYNAMIC TABLE sums
  AS
    SELECT ts_min, sum(c1) FROM intermediate
    GROUP BY 1;
Copy

DISTINCT

GROUPBYALLに相当し、集計関数はありません。

多くの場合、実質的な最適化の機会を意味します。

誤って重複を発生させないためには、DISTINCTをクエリ全体に自由に適用するのが一般的な方法です。増分リフレッシュでは、DISTINCT操作がリフレッシュのたびに重複をチェックする必要があるため、定期的にリソースを消費します。

パフォーマンスを最適化する場合、冗長なDISTINCTsを見つけて削除するのは簡単なことです。これは、さらに上流で重複を排除し、結合のカーディナリティを注意深く検討することで実現します。

<fn> OVER <ウィンドウ>

変更されたパーティションキーごとにウィンドウ関数を再計算することで増分されます。

クエリにPARTITIONBY句があり、ソースデータがパーティションキーでクラスタリングされていることを確認してください。また、変更がパーティションのごく一部(おおよそ<5%)であることを確認してください。

<左> INNERJOIN <右>

左側の変更を右側と結合し、右側の変更を左側と結合することによって増分されます。

接合の片側が小さければ、パフォーマンスは良好となります。結合の片側が頻繁に変更される場合、結合キーでもう片側をクラスタリングするとパフォーマンスが向上する可能性があります。

<左> [{LEFT | RIGHT | FULL }] OUTER JOIN <右>

1つまたは2つのNOTEXISTSでinner-join union-all-edにファクタリングすることで増分し、一致しない値に対してNULLsを計算します。このファクタリングされたクエリは増分されます。

内部結合は図のように増分されます。not-existsは、片側で変更されたキーがもう片側で既に存在していたかどうかをチェックすることで増分されます。

推奨事項:

  • 結合の片側が頻繁に変更される場合、結合キーでもう片側をクラスタリングするとパフォーマンスが向上する可能性があります。

  • 変更頻度の高いテーブルを左側に配置します。

  • OUTERの反対側の変更を最小限に抑えるようにします。LEFTOUTERの場合、右側の変更を最小限に抑えます。

  • FULL結合では、局所性が非常に重要です。

フルリフレッシュでサポートされる非決定性関数

動的テーブルでは、以下の非決定性関数がサポートされています。これらの関数はフルリフレッシュでのみサポートされていることに注意してください。増分リフレッシュでサポートされない内容のリストについては、 増分リフレッシュのサポートに関する制限 をご参照ください。

動的テーブルが他の動的テーブルに依存している場合のデータのリフレッシュ方法

動的テーブルのラグが時間の尺度として指定されている場合、自動リフレッシュプロセスは、動的テーブルのターゲットラグタイムに基づいて、リフレッシュのスケジュールを決定します。このプロセスは、各テーブルのターゲットラグタイムに最適なスケジュールを選択します。

注釈

ターゲットラグは保証ではありません。代わりに、Snowflakeが達成を目指すターゲットです。動的テーブルのデータは、ターゲットラグの範囲内で可能な限りリフレッシュされます。しかし、ウェアハウスのサイズ、データサイズ、クエリの複雑さ、および類似の要因などのために、ターゲットラグを超える可能性があります。

ある動的テーブルが別の動的テーブルに依存 している場合にデータの一貫性を保つために、このプロセスはアカウント内のすべての動的テーブルを互換性のあるタイミングでリフレッシュします。リフレッシュの頻度が低いタイミングは、リフレッシュの頻度が高いタイミングと一致します。

たとえば、動的テーブルAのターゲットラグが2分で、ターゲットラグが1分の動的テーブルBをクエリするとします。このプロセスでは、Aは96秒ごと、Bは48秒ごとにリフレッシュする必要があると判断される可能性があります。その結果、このプロセスは以下のスケジュールを適用する可能性があります。

特定の時点

リフレッシュされる動的テーブル

2022-12-01 00:00:00

A, B

2022-12-01 00:00:48

B

2022-12-01 00:01:36

A, B

2022-12-01 00:02:24

B

つまり、互いに依存する一連の動的テーブルをクエリするときは、いつでも、これらのテーブルにまたがるデータの同じ「スナップショット」をクエリしていることになります。

動的テーブルのターゲットラグは、それが依存する動的テーブルのターゲットラグよりも短くはできないことに注意してください。たとえば、次の場合を考慮します。

  • 動的テーブルAが動的テーブルBとCをクエリします。

  • 動的テーブルBのターゲットラグは5分です。

  • 動的テーブルCのターゲットラグは1分です。

つまり、Aのターゲットラグタイムは5分より短くすることはできません(つまり、BとCのラグタイムの長い方より短くすることはできません)。

Aのラグを5分に設定した場合、プロセスは以下の目標があるリフレッシュスケジュールを設定します。

  • ラグが1分以下になるよう、Cを頻繁にリフレッシュします。

  • AとBを一緒にリフレッシュし、ラグが5分以下になるように十分な頻度でリフレッシュします。

  • スナップショットの分離を確実にするために、AとBのリフレッシュがCのリフレッシュと一致するようにします。

注: リフレッシュに時間がかかりすぎる場合、スケジューラーはリフレッシュをスキップして最新の状態に保とうとすることがあります。ただし、スナップショットの分離は維持されます。