[新機能] Snowflake Dynamic TablesのAdaptive Refresh Modeがパブリックプレビューとなったので試してみた

[新機能] Snowflake Dynamic TablesのAdaptive Refresh Modeがパブリックプレビューとなったので試してみた

2026.05.28

かわばたです。

2026年5月26日にSnowflake Dynamic Tablesの新機能として、Adaptive Refresh ModeがPublic Previewでリリースされました。

従来のDynamic Tablesでは、実行時のリフレッシュ方式はINCREMENTAL(差分リフレッシュ)またはFULL(全体再構築)のいずれかに固定されていました。AUTOを指定した場合も、作成時にINCREMENTALまたはFULLへ解決され、その後は自動で切り替わるものではありませんでした。
Adaptive Refresh Modeでは通常はインクリメンタルリフレッシュを実行しつつ、内部ヒューリスティックにより再初期化(REINITIALIZE)の方が効率的と判断された場合に自動的にREINITIALIZEへ切り替わります。

https://docs.snowflake.com/en/user-guide/dynamic-tables/refresh-modes#label-dynamic-tables-refresh-adaptive

INSERT OVERWRITEによる一括ロードが時折発生するようなワークロードで確認した内容を記載します。

機能概要

Dynamic Tablesの従来のリフレッシュモードは以下の3つでした。

リフレッシュモード 動作
AUTO Snowflakeがクエリ定義に基づいてINCREMENTALまたはFULLを自動選択(作成時に決定)
INCREMENTAL 前回リフレッシュ以降の差分のみを処理
FULL 毎回テーブル全体を再構築

今回追加されたADAPTIVEは、通常はインクリメンタルリフレッシュを実行しつつ、Snowflakeの内部ヒューリスティックにより「差分処理より再初期化の方が効率的」と判断された場合に、自動的にREINITIALIZEを実行するリフレッシュモードです。

  • 通常時: インクリメンタルリフレッシュを実行(差分のみ処理)
  • 大規模変更時: 内部ヒューリスティックが「インクリメンタル処理より再初期化(REINITIALIZE)の方が効率的」と判断した場合、自動的にREINITIALIZEを実行
  • REINITIALIZE後: 再びインクリメンタルリフレッシュに戻る

INSERT OVERWRITEや大量のDELETE/UPDATEは、REINITIALIZEが発動しやすい代表的なケースとして挙げられます。

また、INITIALIZATION_WAREHOUSEパラメータを使うことで、通常のインクリメンタルリフレッシュ用のウェアハウスとは別に、再初期化(REINITIALIZE)用の大きいウェアハウスを指定できます。これにより、通常時は小さいウェアハウスでコストを抑えつつ、REINITIALIZE時だけ大きいウェアハウスで高速に処理するという使い分けが可能です。

REINITIALIZEが発生したかどうかは、DYNAMIC_TABLE_REFRESH_HISTORY関数でREFRESH_ACTION = 'REINITIALIZE'を確認することで監視できます。

制限事項

  • 2026年5月27日時点ではPublic Previewの機能です。GAまでに仕様が変わる可能性があります
  • INCREMENTALモードと同じSQL構文の制限があります(INTERSECTEXCEPT、正確なパーセンタイル関数などは使用不可)
  • 再初期化(REINITIALIZE)の発動タイミングはSnowflakeの内部ヒューリスティックに依存しており、利用者側で直接制御することはできません
  • ADAPTIVEダイナミックテーブルは、他のADAPTIVEまたはINCREMENTALのDynamic Tableの上流・下流に配置できます
  • フルリフレッシュの上流テーブルから下流にADAPTIVEダイナミックテーブルを配置する場合、上流テーブルにシステム派生のユニークキーまたはIMMUTABLE WHERE制約が必要です

コスト

2026年5月27日時点では、公式DocにAdaptive Refresh Mode固有の追加コストに関する記載はありませんでした。ただし、再初期化(REINITIALIZE)が発動するとFULLリフレッシュ相当のコンピュートが発生するため、頻繁にINSERT OVERWRITEが行われる環境ではウェアハウスコストにご注意ください。INITIALIZATION_WAREHOUSEに大きいウェアハウスを指定した場合は、そのウェアハウスのコストが別途発生します。

検証環境

  • Snowflake: AWSリージョン、Enterpriseエディションのトライアルアカウントで検証
  • ウェアハウス: 通常リフレッシュ用(XSMALL)、INITIALIZATION_WAREHOUSE用(MEDIUM)の2つを使用

事前準備

検証用データベース・スキーマ・ウェアハウスの作成

検証用の環境を作成します。通常リフレッシュ用のXSMALLウェアハウスと、REINITIALIZE用のMEDIUMウェアハウスの2つを準備します。

USE ROLE SYSADMIN;

-- データベース・スキーマの作成
CREATE DATABASE IF NOT EXISTS DT_ADAPTIVE_DEMO;
USE DATABASE DT_ADAPTIVE_DEMO;
CREATE SCHEMA IF NOT EXISTS PUBLIC;
USE SCHEMA PUBLIC;

-- 通常リフレッシュ用ウェアハウス
CREATE WAREHOUSE IF NOT EXISTS WH_DT_XS
  WAREHOUSE_SIZE = 'XSMALL'
  AUTO_SUSPEND = 60
  AUTO_RESUME = TRUE;

ベーステーブルの作成とデータ投入

検証用のベーステーブルとして、ECサイトの注文データを10万件生成します。REINITIALIZEの発動にはある程度のデータ量が必要なため、GENERATOR関数を使ってランダムデータを生成します。

USE WAREHOUSE WH_DT_XS;

-- 検証用テーブル(ECサイトの注文データ 10万件)
CREATE OR REPLACE TABLE orders AS
SELECT
  SEQ4() AS order_id,
  'Customer_' || UNIFORM(1, 1000, RANDOM()) AS customer_name,
  ARRAY_CONSTRUCT('Laptop','Phone','Tablet','Monitor','Keyboard','Mouse','Headset','Camera')
    [UNIFORM(0, 7, RANDOM())]::VARCHAR AS product_name,
  DATEADD(day, -UNIFORM(0, 365, RANDOM()), '2026-05-27')::DATE AS order_date,
  UNIFORM(1, 50, RANDOM()) AS quantity,
  ROUND(UNIFORM(10, 500, RANDOM())::NUMERIC(10,2), 2) AS unit_price,
  ROUND(quantity * unit_price, 2) AS total_amount,
  ARRAY_CONSTRUCT('COMPLETED','PENDING','SHIPPED','CANCELLED')
    [UNIFORM(0, 3, RANDOM())]::VARCHAR AS status,
  ARRAY_CONSTRUCT('Tokyo','Osaka','Nagoya','Fukuoka','Sapporo')
    [UNIFORM(0, 4, RANDOM())]::VARCHAR AS region
FROM TABLE(GENERATOR(ROWCOUNT => 100000));

10万件作成されていれば準備完了です。

SELECT COUNT(*) AS row_count FROM orders;

2026-05-27_22h26_33

また、JOINで使用するリージョンマスタテーブルも作成します。

CREATE OR REPLACE TABLE region_master (
  region VARCHAR,
  region_name VARCHAR,
  country VARCHAR
);

INSERT INTO region_master VALUES
  ('Tokyo', '東京', 'Japan'),
  ('Osaka', '大阪', 'Japan'),
  ('Nagoya', '名古屋', 'Japan'),
  ('Fukuoka', '福岡', 'Japan'),
  ('Sapporo', '札幌', 'Japan');

試してみた

Adaptive Refresh ModeでDynamic Tableを作成する

REFRESH_MODE = ADAPTIVEを指定してDynamic Tableを作成します。ここではベーステーブルordersにリージョンマスタテーブルregion_masterをJOINする定義にしています。

CREATE OR REPLACE DYNAMIC TABLE orders_enriched
  TARGET_LAG = '1 minute'
  REFRESH_MODE = ADAPTIVE
  WAREHOUSE = WH_DT_XS
AS
  SELECT
    o.order_id,
    o.customer_name,
    o.product_name,
    o.order_date,
    o.quantity,
    o.total_amount,
    o.status,
    o.region,
    r.region_name,
    r.country
  FROM orders o
  JOIN region_master r ON o.region = r.region;

作成後、SHOW DYNAMIC TABLESREFRESH_MODEADAPTIVEになっていることを確認します。

SHOW DYNAMIC TABLES LIKE 'ORDERS_ENRICHED';

2026-05-27_22h28_19

refresh_mode列がADAPTIVEと表示されていれば問題ありません。

初回リフレッシュが完了するまで少し待ちます(10万行のため1分程度)。
件数が確認できれば初回リフレッシュは成功です。

SELECT COUNT(*) AS row_count FROM orders_enriched;

通常INSERT後のインクリメンタルリフレッシュを確認する

ベーステーブルに少量のデータを追加して、インクリメンタルリフレッシュが行われることを確認します。

-- 100件追加
INSERT INTO orders
SELECT
  100000 + SEQ4() AS order_id,
  'NewCustomer_' || UNIFORM(1, 100, RANDOM()) AS customer_name,
  'Laptop' AS product_name,
  '2026-05-27'::DATE AS order_date,
  UNIFORM(1, 10, RANDOM()) AS quantity,
  ROUND(UNIFORM(50, 200, RANDOM())::NUMERIC(10,2), 2) AS unit_price,
  ROUND(quantity * unit_price, 2) AS total_amount,
  'COMPLETED' AS status,
  'Tokyo' AS region
FROM TABLE(GENERATOR(ROWCOUNT => 100));

TARGET_LAGに指定した1分を目安に、リフレッシュが完了するまで少し待ってから、DYNAMIC_TABLE_REFRESH_HISTORY関数でリフレッシュ履歴を確認します。

SELECT
    name,
    refresh_action,
    refresh_trigger,
    state,
    data_timestamp,
    statistics:numInsertedRows::INT AS inserted_rows,
    statistics:numDeletedRows::INT AS deleted_rows
FROM TABLE(INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(
    NAME => 'DT_ADAPTIVE_DEMO.PUBLIC.ORDERS_ENRICHED'
))
WHERE state = 'SUCCEEDED'
ORDER BY data_timestamp DESC
LIMIT 5;

REFRESH_ACTIONINCREMENTALになっていれば問題ありません。通常のINSERTではインクリメンタルリフレッシュが実行されることが確認できました。少量の追加(100件)に対して差分処理のみで効率的に更新されています。

2026-05-27_22h30_54

INSERT OVERWRITE後のREINITIALIZEを確認する

次に、INSERT OVERWRITEでベーステーブルのデータを一括で書き換え、REINITIALIZEが自動的に発動するか確認します。10万行のうち直近1ヶ月分(約7,000〜8,000件程度)のみに絞り込むことで、大幅なデータ変更を発生させます。

-- INSERT OVERWRITEで全データを書き換え(直近のデータのみに絞る)
-- 10万行 → 約7,000行への大幅削減
INSERT OVERWRITE INTO orders
SELECT * FROM orders WHERE order_date >= '2026-05-01';

2026-05-27_22h31_58

TARGET_LAGに指定した1分を目安に、1〜2分ほど待ってからリフレッシュ履歴を確認します。

SELECT
    name,
    refresh_action,
    refresh_trigger,
    state,
    data_timestamp,
    statistics:numInsertedRows::INT AS inserted_rows,
    statistics:numDeletedRows::INT AS deleted_rows
FROM TABLE(INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY(
    NAME => 'DT_ADAPTIVE_DEMO.PUBLIC.ORDERS_ENRICHED'
))
WHERE state = 'SUCCEEDED'
ORDER BY data_timestamp DESC
LIMIT 5;

REFRESH_ACTIONREINITIALIZEになっていればOKです。実際の検証では、INSERT OVERWRITE実行から約1〜2分後にREINITIALIZEが発動し、inserted_rows = 8671deleted_rows = 100,000という結果を確認しました。

2026-05-27_22h32_40

最後に

Snowflake Dynamic Tablesの新機能であるAdaptive Refresh Modeを試しました。

10万行のデータで検証した結果、通常のINSERTではインクリメンタルリフレッシュが実行され、INSERT OVERWRITEで大幅なデータ変更を行った際にはREINITIALIZEが自動的に発動することを確認できました。

「普段は差分更新だけど、たまに一括ロードが走る」というワークロードでは、従来のようにリフレッシュモードを手動で切り替える必要がなくなるため、運用が楽になりそうです。

この記事が何かの参考になれば幸いです!


Snowflakeの導入支援はクラスメソッドに!

クラスメソッドでは Snowflake の導入を支援しております。
製品の詳細や支援の内容についてお気軽にお問い合わせください。

Snowflakeの詳細を見る

この記事をシェアする

関連記事