When building data pipelines in Snowflake, choosing between Dynamic Tables and Streams + Tasks is a critical architectural decision. The two follow completely different paradigms and suit different use cases. This article compares them across 7 axes and gives you a framework for making the call.
Dynamic Tables are declarative. You simply declare "keep the result of this SELECT statement up to date," and Snowflake handles change detection, incremental processing, and refresh scheduling for you.
Streams + Tasks are imperative. You explicitly code the steps: use a Stream to capture CDC (change data capture) and a Task to run MERGE/INSERT statements. Transformation logic, execution order, and error handling are all under your control.
-- 宣言型: Dynamic Table
CREATE DYNAMIC TABLE gold_revenue
TARGET_LAG = '10 minutes'
WAREHOUSE = etl_wh
AS
SELECT region, SUM(amount) AS total_revenue
FROM silver_orders
GROUP BY region;
-- 手続型: Stream + Task
CREATE STREAM orders_stream ON TABLE silver_orders;
CREATE TASK merge_revenue
WAREHOUSE = etl_wh
SCHEDULE = 'USING CRON */10 * * * * UTC'
WHEN SYSTEM$STREAM_HAS_DATA('orders_stream')
AS
MERGE INTO gold_revenue t
USING (
SELECT region, SUM(amount) AS total_revenue
FROM orders_stream
GROUP BY region
) s ON t.region = s.region
WHEN MATCHED THEN UPDATE SET t.total_revenue = t.total_revenue + s.total_revenue
WHEN NOT MATCHED THEN INSERT (region, total_revenue) VALUES (s.region, s.total_revenue);| Aspect | Dynamic Tables | Streams + Tasks |
|---|---|---|
| Latency control | TARGET_LAG (declare max acceptable latency) | CRON schedule (explicit execution interval) |
| Specify "run at minute 0 of every hour" | Not supported (lag-based control only) | Yes (strict CRON expression) |
| Behavior when there are no changes | Refresh is skipped automatically | Skip explicitly via the WHEN clause |
| End-to-end DAG SLA management | Automatically derived from leaf-node TARGET_LAG | Each Task schedule must be designed individually |
| Item | Dynamic Tables | Streams + Tasks |
|---|---|---|
| Initial code volume | Small (CREATE DYNAMIC TABLE + SELECT) | Larger (Stream + Task + MERGE/INSERT statements) |
| Handling schema changes | Edit the SELECT and REPLACE | Recreate Stream + edit Task + re-schedule |
| Recovery from failures | Automatic retry; manual REFRESH available | Check Task error logs → check Stream offset → re-run manually |
| Testability | The SELECT can be tested in isolation | Stream consumption is not idempotent, so retesting takes care |
Dynamic Tables let you write any JOIN inside the SELECT, and Snowflake tracks every upstream table for you. With Streams + Tasks, a Stream is created on a single table (or view), so to JOIN changes from multiple tables you either create multiple Streams and combine them inside the Task, or design around the timing skew of change detection across sources.
-- Dynamic Tables: JOINを含むSELECTをそのまま宣言
CREATE DYNAMIC TABLE enriched_orders
TARGET_LAG = '5 minutes'
WAREHOUSE = etl_wh
AS
SELECT
o.order_id,
o.order_date,
p.product_name,
p.category,
o.quantity * p.unit_price AS line_total
FROM raw_orders o
JOIN raw_products p ON o.product_id = p.product_id;
-- Streams/Tasks: 複数Streamの管理が必要
CREATE STREAM orders_cdc ON TABLE raw_orders;
CREATE STREAM products_cdc ON TABLE raw_products;
-- → Task内で両Streamを参照し、MERGEロジックを実装
-- → 片方のStreamだけにデータがあるケースの処理が必要Dynamic Tables' incremental refresh is detected and executed automatically by Snowflake. You write the SELECT without worrying about refresh mode. Keep in mind, though, that queries containing WINDOW functions or SELECT DISTINCT fall back to Full Refresh.
With Streams + Tasks, the Stream exposes INSERT/UPDATE/DELETE rows through columns like METADATA$ACTION, so you can write a MERGE statement that handles incremental processing with fine-grained precision. Tracking DELETE operations or comparing before/after values on UPDATEs are all possible.
| Cost item | Dynamic Tables | Streams + Tasks |
|---|---|---|
| Compute cost | Credits on the specified warehouse | Credits on the specified warehouse |
| Storage cost | Storage for the materialized table | Storage for the target table |
| Cost when there are no changes | Refresh skipped (effectively zero) | Skipped via WHEN clause (effectively zero) |
| When a Full Refresh occurs | Costs can spike on large tables | Stream-based: only deltas are processed |
| Monitoring view | DYNAMIC_TABLE_REFRESH_HISTORY | TASK_HISTORY / STREAM_HAS_DATA |
-- Dynamic Tablesのリフレッシュ監視
SELECT name, refresh_action, state, data_timestamp
FROM TABLE(INFORMATION_SCHEMA.DYNAMIC_TABLE_REFRESH_HISTORY())
WHERE state = 'FAILED'
ORDER BY refresh_start_time DESC
LIMIT 10;
-- Streams/Tasksの実行監視
SELECT name, state, error_message, scheduled_time
FROM TABLE(INFORMATION_SCHEMA.TASK_HISTORY(
SCHEDULED_TIME_RANGE_START => DATEADD(HOUR, -24, CURRENT_TIMESTAMP())
))
WHERE state = 'FAILED'
ORDER BY scheduled_time DESC;パイプラインの要件は?
│
├─ SELECT文で表現可能な変換か?
│ ├─ YES → JOINや集計が中心か?
│ │ ├─ YES → Dynamic Tables推奨
│ │ └─ NO(条件分岐・外部連携あり)→ Streams/Tasks
│ └─ NO(ストアドプロシージャが必要)→ Streams/Tasks
│
├─ 厳密なCRONスケジュールが必要か?
│ ├─ YES(毎時0分に実行等)→ Streams/Tasks
│ └─ NO(最大遅延指定でOK)→ Dynamic Tables
│
├─ DELETE/UPDATEの変更前後の値を追跡する必要があるか?
│ ├─ YES → Streams/Tasks(METADATA$ACTION / $ISUPDATE)
│ └─ NO → Dynamic Tables
│
└─ 運用負荷を最小化したいか?
├─ YES → Dynamic Tables
└─ 細かい制御が必要 → Streams/Tasks| Axis | Dynamic Tables | Streams + Tasks |
|---|---|---|
| 1. Paradigm | Declarative | Imperative |
| 2. SLA control | TARGET_LAG (max latency) | CRON (execution timing) |
| 3. Complexity | Low (just a SELECT) | High (Stream + Task + MERGE) |
| 4. JOIN | Write freely inside the SELECT | Requires managing multiple Streams |
| 5. Incremental logic | Auto-detected | Manual (fine-grained control) |
| 6. Cost | Watch out for Full Refreshes | Always processes deltas only |
| 7. Monitoring | REFRESH_HISTORY | TASK_HISTORY |
Data Engineering
問題 1
A team operates a pipeline that detects changes on an orders table and updates an aggregate table via MERGE. The requirements are: (1) run exactly at 06:00 UTC every day, and (2) use the pre-change values of DELETEd rows to perform rollback aggregation. Which implementation approach is most appropriate?
正解: C
Two of the requirements — a strict CRON-based schedule ("exactly 06:00 UTC every day") and fine-grained incremental control ("track pre/post values of DELETE rows") — are both outside what Dynamic Tables can do. Streams/Tasks can specify the schedule via CRON and identify DELETE/UPDATE rows through the Stream's METADATA$ACTION and METADATA$ISUPDATE columns. Materialized Views are limited to aggregations on a single table and do not support MERGE operations.
Can Dynamic Tables and Streams/Tasks coexist in the same pipeline?
Yes, they coexist well. For example, you can capture changes on a Dynamic Table with a Stream and then fan out to external tables or email notifications via a Task. Change Tracking is automatically enabled when a Dynamic Table is used as a Stream source, so no extra configuration is required. Because the dependency graph can get complex, plan DAG visualization and alerting up front.
What should I watch out for when migrating from Streams/Tasks to Dynamic Tables?
The biggest gotcha is that Stream offsets (consumption position) do not carry over to Dynamic Tables. A Dynamic Table performs a Full Refresh on initial creation, so plan your cutover carefully to avoid duplicate processing during the migration window. Also note that Dynamic Tables cannot use strict CRON schedules — they rely on TARGET_LAG to declare maximum latency — so any pipeline with strict execution-order dependencies needs a design review.
Which is cheaper to run?
It depends. For simple ETL pipelines, Dynamic Tables tend to be cheaper thanks to automatic incremental-refresh optimization. On the other hand, Streams/Tasks let you skip Task execution entirely when there is no new data (WHEN SYSTEM$STREAM_HAS_DATA), so for tables that change very infrequently Streams/Tasks can consume fewer credits. Either way, measure actual credit consumption against the refresh-history views in ACCOUNT_USAGE before deciding.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
Snowflake Certifications: All 11 Exams Explained (2026)
Every SnowPro certification — Associate, Core, Specialty, Ad...
Snowflake Exam Difficulty Ranking: All 11 Certs Compared (2026)
All 11 SnowPro exams ranked by difficulty with study-time es...
Snowflake Study Guide: Fastest Pass Route by Exam (2026)
How to pass SnowPro certifications efficiently — official ma...
SnowPro Core (COF-C03): Complete Exam Guide (2026)
Pass the SnowPro Core exam — six domains, scope, sample ques...
SnowPro Associate Platform (SOL-C01): Complete Guide (2026)
The entry-level SnowPro Associate exam — scope, weighting, s...