❄️

マテリアライズドビュー vs ダイナミックテーブル:Snowflakeの「結果保持」技術、どう使い分ける?

に公開

🚀 はじめに

Snowflakeを使っていて、こんなことを考えたことはありませんか?

  • 「この集計クエリ、重いから結果をキャッシュ(実体化)して高速化したい」
  • 「ELT処理の途中で作る中間テーブル、手動のCREATE TABLE AS SELECT (CTAS)Stream/Task で管理するのが面倒...」

これまでSnowflakeでは、前者のニーズにマテリアライズドビュー(MV)、後者は Stream/Task を組み合わせて実装するのが一般的でしたが、近年は ダイナミックテーブル(DT) が登場し、後者のデータパイプライン構築を大幅に簡素化できるようになりました。

両者はいずれも「クエリ結果を保持」しますが、目的と仕組みは本質的に異なります。この記事では相違点と使い分けを整理します。

https://zenn.dev/yujmatsu/articles/20251023_sf_performance

結論から:使い分けの早見表

比較軸 マテリアライズドビュー(MV) ダイナミックテーブル(DT)
主な目的 クエリの高速化(パフォーマンス) データ変換(データパイプライン)
SQL自由度 非常に低い(単一テーブル前提、JOIN不可、許可集計関数は限定) 高い(JOIN・ウィンドウ等も広く対応するがモード別制約あり
更新方式 ベースDMLに追随し自動・増分メンテナンス(必要に応じベース併用で常に最新結果を返す TARGET_LAG に基づくスケジュールで増分/フルの自動更新(AUTO を含む)
クエリ透過性 あり(オプティマイザが自動書き換え) なし(ダイナミックテーブル名を直接参照)
コスト構造 **自動維持(サーバレス)**に係るコスト+ストレージ リフレッシュ時に使うWHの実行コスト+ストレージ
一言でいうと 高速化のための「自動キャッシュ 宣言的な「データパイプライン

1. マテリアライズドビュー(MV)とは?

マテリアライズドビューは、一言でいうと「クエリパフォーマンスを劇的に向上させるための自動キャッシュ」です。

目的と仕組み

目的は、頻繁かつ高コストな集計やフィルタを前計算して高速化することです。ユーザーがベーステーブルを叩いているつもりでも、条件が合えばオプティマイザが自動的にマテリアライズドビューへ書き換え、透過的に高速化されます。

Snowflakeのマテリアライズドビューは、ベーステーブルのDML(変更)に追随して非同期・増分で自動メンテナンスされます。もし一部が未反映の瞬間でも、マテリアライズドビューとベーステーブルの両方を参照し、常に最新の現在データを返すことが保証されています。

致命的な「制約」

この強力な「自動・増分メンテナンス」と「クエリ透過性」を維持するため、Snowflakeのマテリアライズドビューには非常に厳しいSQL制約があります。

  • 単一テーブル前提: JOIN不可(自己結合含む)。
  • 関数・構文の制限: ウィンドウ関数、HAVING、ORDER BY、LIMIT、EXCEPT/INTERSECT、複雑なサブクエリなどは使用不可。
  • 集計関数の制限: 許可される集計関数は限定的(例:SUM, COUNT, AVG, MAX, MIN 等)。
  • 参照の制限: UDF/UDTF や他のビュー、ダイナミックテーブルの参照は不可。

※ただし、クエリ側でマテリアライズドビューを他表とJOINすること自体は可能です(マテリアライズドビューは“事前計算済みテーブル”のように扱えます)。

2. ダイナミックテーブル(DT)とは?

ダイナミックテーブルは、一言でいうと「宣言的なデータパイプライン」です。

目的と仕組み

目的は、SELECT 一発で宣言的にデータパイプラインを定義し、Streams/Tasksの煩雑な依存関係管理を置き換えることです。

定義した TARGET_LAG(目標鮮度)に基づき、Snowflakeが自動スケジューリングでリフレッシュ(更新)を行います。

増分リフレッシュ(差分更新)を有効にするためには、ベーステーブルのChange Tracking(Time Travelが有効であること)が必要です。

-- "staging層" と "raw層" をJOINして、"analytics層" のダイナミックテーブルを作る
CREATE OR REPLACE DYNAMIC TABLE analytics.product_summary
TARGET_LAG = '1 HOUR'
WAREHOUSE  = etl_wh
AS
SELECT
    s.product_id,
    r.product_name,
    SUM(s.quantity) AS total_quantity
FROM staging.sales s
JOIN raw.products r ON r.product_id = s.product_id
GROUP BY 1, 2;

自由度と制約のバランス

ダイナミックテーブルは、マテリアライズドビューよりはるかにSQLの自由度が高いです。

  • JOIN、UNION ALL、ウィンドウ関数、CTE など幅広く対応します。
  • 制約(重要):
    • 外部関数は不可です。UDFは条件付きで可能です。
    • 増分リフレッシュには構文上の制約があり、対応していない構文(一部のOUTA JOINや集合演算など)が使われている場合、フルリフレッシュ(全件洗い替え)にフォールバックします。
    • クエリリライトの対象ではないため、ダイナミックテーブル名を明示的にSELECTする必要があります。

3. どう使い分けるか

  • ユースケース1:BI ダッシュボードが重い(既存クエリを変えずに速くしたい)
    \rightarrow マテリアライズドビュー(MV) を選びます。
    オプティマイザの自動書き換え(クエリ透過性)により、利用者に影響を与えず高速化できます。

  • ユースケース2:ELTパイプラインを宣言的に構築したい(Raw \rightarrow Staging \rightarrow Marts の変換を定義したい)
    \rightarrow ダイナミックテーブル(DT) を選びます。
    複雑なSQLをそのまま定義でき、TARGET_LAG に基づいて鮮度管理も任せられるため、Streams/Tasksの置き換えに適しています。

補足:Snowflake マテリアライズドビューの特殊性 (他社製品との比較)

「マテリアライズドビューは制約が厳しい」と聞くと、他社の製品を知っている方は驚くかもしれません。
Snowflakeは「自動・差分維持+透過的書き換え」を保証する代わりに、定義時のSQL制約が他製品より厳格になっています。

製品 リフレッシュのトリガー 更新方式 SQLの自由度 クエリ透過性
Snowflake 自動・増分(DML連動) 差分 (Incremental) 非常に低い あり
Oracle 自動(ON COMMIT) / スケジュール / 手動 FAST(差分) / COMPLETE(フル)を選択可 中〜高(FAST時は制約あり) あり (QUERY REWRITE)
BigQuery 自動(一定時間内) / 手動 差分 (対応クエリのみ) 中 (JOIN制限等あり) あり
Redshift 自動 (AUTO REFRESH) / 手動 差分 (対応クエリのみ) 中 (JOIN制限等あり) あり
PostgreSQL 手動 (REFRESH) フル (ブロック) 高い なし(標準では)

😌 おわりに

「クエリを速くしたい」ならマテリアライズドビュー、「データを作りたい/整えたい」ならダイナミックテーブル、が基本原則です。
似た名前でも、マテリアライズドビューはパフォーマンス最適化、ダイナミックテーブルはデータパイプライン構築のための機能です。目的・透過性・制約を理解し、要件に最適なアプローチを選びましょう。

📚 参考出典(主要ドキュメント)

Discussion