不変性制約の使用

動的テーブルの特定の行が変更されないことをSnowflakeに指示するには、 CREATE DYNAMIC TABLEIMMUTABLE WHERE 句または ALTER DYNAMIC TABLE ステートメントを使用します。

不変性は、変更されない行をスキップすることでリフレッシュを高速化します。不変性のある バックフィル は、即時および継続的なパフォーマンス上のメリットを提供します。

  • 初期作成 :バックフィルは、計算コストなしで履歴データを即座にコピーします。これにより、何年もの履歴データを含むテーブルが、コストのかかる初期リフレッシュを必要とせずにすぐに利用できるようになります。

  • 継続的な更新 :不変性制約は、将来のリフレッシュ時にバックフィルされたデータを再処理から保護します。可変リージョンのみがリフレッシュされ、テーブルが大きくになってもリフレッシュ時間を高速化します。

概念的な背景については、 Understanding immutability constraints をご参照ください。

基本的な例

例:ディメンションテーブルが変更された場合の再計算を防止する

ディメンションテーブルの行を更新すると、可変期間のファクトのみが再処理されます。

CREATE DYNAMIC TABLE joined_data
  TARGET_LAG = '1 minute'
  WAREHOUSE = mywh
  IMMUTABLE WHERE (timestamp_col < CURRENT_TIMESTAMP() - INTERVAL '1 day')
AS
  SELECT F.primary_key primary_key, F.timestamp_col timestamp_col, D.value dim_value
  FROM fact_table F
  LEFT OUTER JOIN dimension_table D USING (primary_key);
Copy

例:ソーステーブルよりも長いデータを保持する

ステージングテーブルよりも長い解析済みデータを保持する動的テーブルを作成し、タスクで古いステージングデータを削除します。

CREATE TABLE staging_data (raw TEXT, ts TIMESTAMP);

CREATE DYNAMIC TABLE parsed_data
  TARGET_LAG = '1 minute'
  WAREHOUSE = mywh
  IMMUTABLE WHERE (ts < CURRENT_TIMESTAMP() - INTERVAL '7 days')
AS
  SELECT
    parse_json(raw):event_id::string event_id,
    parse_json(raw):name::string name,
    parse_json(raw):region::string region,
    ts
  FROM staging_data
  WHERE region = 'US';

CREATE TASK delete_old_staging_data
  WAREHOUSE = mywh
  SCHEDULE = '24 hours'
AS
  DELETE FROM staging_data WHERE ts < CURRENT_TIMESTAMP() - INTERVAL '30 days';
Copy

例:下流のテーブルがフルリフレッシュテーブルからインクリメンタルリフレッシュを使用できるようにする

一部のクエリ構成(Pythonユーザー定義テーブル関数など)には、フルリフレッシュモードが必要です。不変性制約により、下流のテーブルは引き続きインクリメンタルリフレッシュを使用できます。

CREATE DYNAMIC TABLE udtf_dt
  TARGET_LAG = '1 hour'
  WAREHOUSE = mywh
  REFRESH_MODE = FULL
  IMMUTABLE WHERE (ts < current_timestamp() - interval '1 day')
AS
  SELECT ts, data, output, join_key
  FROM input_table, TABLE(my_udtf(data));

CREATE DYNAMIC TABLE incremental_join_dt
  TARGET_LAG = '1 hour'
  WAREHOUSE = mywh
  REFRESH_MODE = INCREMENTAL
  IMMUTABLE WHERE (ts < current_timestamp() - interval '1 day')
AS
  SELECT * FROM udtf_dt JOIN dim_table USING (join_key);
Copy

バックフィルの例

以下の例では、バックフィルされたデータを持つテーブルから新しい動的テーブルを作成する方法を示します。

バックフィルテーブルには、動的テーブルと同じ順序で、互換性のあるデータ型の一致する列が含まれている必要があります。Snowflakeはバックフィルテーブルからテーブルプロパティや権限をコピーしません。

Time Travelパラメーター AT | BEFORE を指定した場合、Snowflakeは指定した時間にバックフィルテーブルからデータをコピーします。

不変性制約 とバックフィルデータで作業する場合、以下の制限が適用されます。

  • 現在、バックフィルに使用できるのは通常のテーブルと動的テーブルのみです。

  • ポリシーやタグはバックフィルテーブルからコピーされるため、新しい動的テーブルでは指定できません。

  • 新しい動的テーブルとバックフィルテーブルのクラスタリングキーは同じである必要があります。

例:テーブルの一部からのバックフィル

次の例では、my_backfill_table から my_dynamic_table の不変リージョンを、さらに動的テーブルの定義から可変リージョンをバックフィルします。

この動的テーブルを再初期化する場合:

  • インクリメンタルリフレッシュモード :Snowflakeはすべての可変行を削除し、可変リージョンのみを再入力します。

  • フルリフレッシュモード :Snowflakeは、同じ効果でフルリフレッシュを実行します。

CREATE DYNAMIC TABLE my_dynamic_table (day TIMESTAMP, totalSales NUMBER)
  IMMUTABLE WHERE (day < '2025-01-01')
  BACKFILL FROM my_backfill_table
  TARGET_LAG = '20 minutes'
  WAREHOUSE = 'mywh'
  AS SELECT DATE_TRUNC('day', ts) AS day, sum(price)
    FROM my_base_table
    GROUP BY day;
Copy

例:バックフィルを使用して、動的テーブルのデータを回復または変更する

動的テーブルのデータや定義を直接編集することはできません。データを回復または修正するには、次の回避策の手順を完了します。

  1. 動的テーブルを通常のテーブルにクローンします。

  2. 必要に応じて、クローンされたテーブルを変更します。

  3. 編集されたテーブルから新しい動的テーブルにバックフィルします。

次の例では my_dynamic_tablesales ベーステーブルから日次販売データを集計します。

CREATE OR REPLACE TABLE sales(item_id INT, ts TIMESTAMP, sales_price FLOAT);

INSERT INTO sales VALUES (1, '2025-05-01 01:00:00', 10.0), (1, '2025-05-01 02:00:00', 15.0), (1, '2025-05-01 03:00:00', 11.0);
INSERT INTO sales VALUES (1, '2025-05-02 00:00:00', 11.0), (1, '2025-05-02 05:00:00', 13.0);


CREATE DYNAMIC TABLE my_dynamic_table
  TARGET_LAG = 'DOWNSTREAM'
  WAREHOUSE = mywh
  INITIALIZE = on_create
  IMMUTABLE WHERE (day <= '2025-05-01')
  AS
    SELECT item_id, date_trunc('DAY', ts) day, count(sales_price) AS sales_count FROM sales
    GROUP BY item_id, day;

SELECT item_id, to_char(day, 'YYYY-MM-DD') AS day, sales_count FROM my_dynamic_table;
Copy
+---------+------------+-------------+
| ITEM_ID | DAY        | SALES_COUNT |
|---------+------------+-------------|
| 1       | 2025-05-01 | 3           |
| 1       | 2025-05-02 | 2           |
+---------+------------+-------------+

オプションで、古いデータをアーカイブしてストレージコストを節約できます。

DELETE FROM sales WHERE ts < '2025-05-02';

ALTER DYNAMIC TABLE my_dynamic_table REFRESH;

SELECT item_id, to_char(day, 'YYYY-MM-DD') AS day, sales_count FROM my_dynamic_table;
Copy

その後、2025-05-01 で販売エラーを見つけます。条件: sales_count は2である必要があります。これを修正するには

  1. my_dynamic_table を通常のテーブルにクローンします。

    CREATE OR REPLACE TABLE my_dt_clone_table CLONE my_dynamic_table;
    
    Copy
  2. クローンされたテーブルを更新します。

    UPDATE my_dt_clone_table SET
      sales_count = 2
      WHERE day = '2025-05-01';
    
    SELECT item_id, to_char(day, 'YYYY-MM-DD') AS day, sales_count FROM my_dt_clone_table;
    
    Copy
    +---------+------------+-------------+
    | ITEM_ID | DAY        | SALES_COUNT |
    |---------+------------+-------------|
    | 1       | 2025-05-01 | 2           |
    | 1       | 2025-05-02 | 2           |
    +---------+------------+-------------+
    
  3. 編集されたクローンをバックフィルのソースとして使用し、動的テーブルを再作成します。

    CREATE OR REPLACE DYNAMIC TABLE my_dynamic_table
      BACKFILL FROM my_dt_clone_table
      IMMUTABLE WHERE (day <= '2025-05-01')
      TARGET_LAG = 'DOWNSTREAM'
      WAREHOUSE = mywh
      INITIALIZE = on_create
      AS
        SELECT item_id, date_trunc('DAY', ts) day, count(sales_price) AS sales_count FROM sales
        GROUP BY item_id, day;
    
    Copy

    この手法により、ベーステーブルを変更することなく、動的テーブルのデータを回復または修正できます。

    SELECT item_id, to_char(day, 'YYYY-MM-DD') AS day, sales_count FROM my_dynamic_table;
    
    Copy
    +---------+------------+-------------+
    | ITEM_ID | DAY        | SALES_COUNT |
    |---------+------------+-------------|
    | 1       | 2025-05-01 | 2           |
    | 1       | 2025-05-02 | 2           |
    +---------+------------+-------------+
    

例:バックフィルを使用して動的テーブルのスキーマを変更する

動的テーブルのスキーマを直接変更することはできません。スキーマを更新する場合(たとえば、列を追加するなど)は、次のステップに従います。

  1. 動的テーブルを通常のテーブルにクローンします。次の例では、 sales`(:ref:`前述の <label-data-surgery-example>)から作成した my_dynamic_table を使用します。

    CREATE OR REPLACE TABLE my_dt_clone_table CLONE my_dynamic_table;
    
    Copy
  2. クローンされたテーブルのスキーマを変更します。

    ALTER TABLE my_dt_clone_table ADD COLUMN sales_avg FLOAT;
    
    SELECT item_id, to_char(day, 'YYYY-MM-DD') as DAY, SALES_COUNT, SALES_AVG FROM my_dt_clone_table;
    
    Copy
  3. オプションで、新しい列にデータを追加します。

  4. 編集されたクローンをバックフィルのソースとして使用し、動的テーブルを再作成します。

    CREATE OR REPLACE DYNAMIC TABLE my_dynamic_table
      BACKFILL FROM my_dt_clone_table
      IMMUTABLE WHERE (day <= '2025-05-01')
      TARGET_LAG = 'DOWNSTREAM'
      WAREHOUSE = mywh
      INITIALIZE = on_create
      AS
        SELECT item_id, date_trunc('DAY', ts) day, count(sales_price) AS sales_count, avg(sales_price) as sales_avg FROM sales
        GROUP BY item_id, day;
    
    Copy
  5. 新しい列が動的テーブルに表示されることを確認します。

    SELECT item_id, to_char(day, 'YYYY-MM-DD') as DAY, SALES_COUNT, SALES_AVG, metadata$is_immutable as IMMUTABLE from my_dynamic_table ORDER BY ITEM_ID, DAY;
    
    Copy
    +---------+------------+-------------+-----------+-----------+
    | ITEM_ID | DAY        | SALES_COUNT | SALES_AVG | IMMUTABLE |
    |---------+------------+-------------|-----------|-----------|
    | 1       | 2025-05-01 | 3           | NULL      | TRUE      |
    | 1       | 2025-05-02 | 2           | 12        | FALSE     |
    +---------+-------------+------------+-----------+-----------+
    

不変性ステータスを確認

動的テーブルで行が可変かどうかを確認するには、 METADATA$IS_IMMUTABLE 列をクエリします。

SELECT *, METADATA$IS_IMMUTABLE FROM my_dynamic_table;
Copy

動的テーブルの不変性制約を表示するには、 SHOW DYNAMIC TABLES を実行し、 immutable_where 列を確認します。