❄️ Warehouse & Modeling · Chapter 9
Time travel, zero-copy clones, streams and tasks
Immutable micro-partitions give Snowflake four superpowers for free: query the past, undo a bad DELETE, copy a 20 TB database in seconds, and know exactly which rows changed since you last looked.
Study this lesson free in the app →
The basics
Because Snowflake never edits micro-partitions in place — every change writes new files and keeps the old ones for a while — it can offer four features almost for free:
- Time travel — query or restore a table as it was at an earlier time, within a retention window.
- Zero-copy clone — create a full copy of a table, schema or database instantly, by copying metadata pointers instead of data.
- Streams — an object that tracks what changed in a table since you last consumed it (change data capture inside the warehouse).
- Tasks — scheduled SQL inside Snowflake, often triggered only when a stream has new data.
Why they matter: they replace a pile of external machinery — backup jobs, test-environment copies, CDC tooling, a scheduler for simple incremental loads.
The mental model: a notebook written in pen where you never erase, only add new pages. Time travel is flipping back. A clone is a second bookmark into the same pages. A stream is a sticky note saying "read up to here".
Words you must know 4
- retention period
- how long old versions are kept
- fail-safe
- a further 7-day recovery window only Snowflake support can use
- offset
- a stream's bookmark
- task graph
- tasks chained with AFTER
Explained
Thursday, 4:47 pm. An engineer at Meghalaya Cabs runs:
DELETE FROM fact_rides WHERE city_key = 7; -- meant: in the dev schema31 million Guwahati rides, gone from production.
4:52 pm. One statement later, they're back — no backup restore, no ticket, no data copied:
INSERT INTO fact_rides
SELECT * FROM fact_rides BEFORE(STATEMENT => '01b2c3d4-...')
WHERE city_key = 7;Time travel and fail-safe, precisely
Retention is set by DATA_RETENTION_TIME_IN_DAYS on the account, database, schema or table:
- Default 1 day
- Standard edition: 0 or 1
- Enterprise and above: 0–90 days for permanent tables
- Transient / temporary tables: 0 or 1
During retention you can:
- Query the past:
AT(TIMESTAMP => …),AT(OFFSET => -seconds),BEFORE(STATEMENT => 'query_id') - Restore dropped objects:
UNDROP TABLE / SCHEMA / DATABASE - Materialise a past state:
CREATE TABLE … CLONE … AT(…)
After retention, permanent tables enter fail-safe for 7 more days. You cannot query it; only Snowflake support can recover from it, as a disaster-recovery last resort. Transient and temporary tables have no fail-safe — which is why staging tables are often transient: cheaper storage, accepted risk.
Cost: every micro-partition replaced by DML stays billable through retention + fail-safe. A table rewritten daily with 90-day retention can store ~90× its live size.
Time travel and clones in practice
-- What did yesterday's dashboard see?
SELECT city_key, SUM(fare_inr)
FROM fact_rides AT(TIMESTAMP => '2026-11-04 09:00:00 +0530'::timestamp_tz)
GROUP BY 1;
-- State 1 hour ago
SELECT COUNT(*) FROM dim_driver AT(OFFSET => -3600);
-- Undo a dropped table
DROP TABLE dim_zone;
UNDROP TABLE dim_zone;
-- Restore a table to just before a bad MERGE
CREATE OR REPLACE TABLE fact_rides_restored
CLONE fact_rides BEFORE(STATEMENT => '01b2c3d4-0000-...');
ALTER TABLE fact_rides SWAP WITH fact_rides_restored;
-- A full production copy for testing a migration, in seconds
CREATE DATABASE analytics_dev CLONE analytics;
-- Longer retention only where it earns its storage
ALTER TABLE fact_rides SET DATA_RETENTION_TIME_IN_DAYS = 14;
CREATE TRANSIENT TABLE stg_rides_raw (...); -- no fail-safe, cheapSWAP WITH exchanges two tables atomically, so readers never see a half-restored table.
What a clone shares
CREATE DATABASE analytics_dev CLONE analytics; (20 TB, ~3 s)
analytics → [MP-1] [MP-2] [MP-3] … [MP-96000]
analytics_dev → [MP-1] [MP-2] [MP-3] … [MP-96000] same files
new storage: 0
UPDATE analytics_dev.marts.fact_rides SET … WHERE city_key = 7;
analytics → [MP-1] [MP-2 ] [MP-3] …
analytics_dev → [MP-1] [MP-2'] [MP-3] … only MP-2' is new storageThe clone is a fully independent, writable object. Changes on either side never affect the other — they just stop sharing those files.
Stream + task = incremental pipeline in pure SQL
CREATE STREAM stg_rides_s ON TABLE stg_rides;
CREATE TASK load_fact_rides
WAREHOUSE = elt_wh
SCHEDULE = '5 MINUTE'
WHEN SYSTEM$STREAM_HAS_DATA('STG_RIDES_S') -- no data → no warehouse
AS
MERGE INTO fact_rides f
USING (SELECT * FROM stg_rides_s
WHERE METADATA$ACTION = 'INSERT') s -- inserts + new side of updates
ON f.ride_id = s.ride_id
WHEN MATCHED THEN UPDATE SET f.fare_inr = s.fare_inr
WHEN NOT MATCHED THEN INSERT (ride_id, driver_key, fare_inr)
VALUES (s.ride_id, s.driver_key, s.fare_inr);
-- Downstream step runs only after the root task finishes
CREATE TASK refresh_driver_daily
WAREHOUSE = elt_wh
AFTER load_fact_rides
AS CALL sp_refresh_driver_daily();
-- Tasks are created SUSPENDED: resume children first, then the root
ALTER TASK refresh_driver_daily RESUME;
ALTER TASK load_fact_rides RESUME;Omit WAREHOUSE to make it a serverless task — Snowflake sizes compute itself and bills it as serverless credits.
At production scale
- Retention is a storage dial. 90 days on a 2 TB append-only fact is cheap; 90 days on a table fully rewritten every night is ~180 TB of history. Use long retention on precious, low-churn tables; transient for re-creatable staging
- Clones make dev environments honest. Nightly
CREATE DATABASE analytics_ci CLONE analyticsgives every PR's dbt run real data at zero copy cost — only what tests modify gets stored - One stream per consumer. Two pipelines reading one stream: the first to commit advances the offset and the second misses the changes
- Staleness is an outage. If a stream isn't consumed within the table's retention (Snowflake extends it up to
MAX_DATA_EXTENSION_TIME_IN_DAYS, default 14), it goes stale and must be recreated — and the changes in between need a backfill. MonitorSHOW STREAMS→stale_after - Tasks are simple orchestration. Great for stream-driven incremental loads inside Snowflake; for cross-system dependencies, retries with alerting and backfills, an external orchestrator (Airflow, Dagster) still wins
Gotchas
- Noticing the bad DELETE on day 3 with 1-day retention — time travel is gone; only fail-safe via support remains (and nothing at all for transient tables)
- Thinking fail-safe is a backup you control — it isn't queryable and isn't guaranteed for convenience restores
- Forgetting
ALTER TASK … RESUME— tasks are created suspended; the pipeline silently never runs - Testing a stream with SELECT and expecting it to be 'used up' — only committed DML advances it
- Updates arrive as DELETE + INSERT pairs — a MERGE that treats every DELETE row as a real delete will wipe updated rows; filter on
METADATA$ISUPDATE - Long retention on churny tables — a quiet storage bill multiplier
- Cloning and assuming it's a backup — a clone shares files, but it's a separate object that survives the source being dropped; it's a point-in-time copy, not continuous protection
Old files are kept, so the past is queryable. Time travel = flip back; clone = second pointer; stream = bookmark; task = standing instruction.
Retention 1 day default (Enterprise up to 90) → then 7 days fail-safe, support-only.
Streams move only on committed DML. Tasks start suspended.
Words to know
| Time travel | Querying, cloning or restoring data as of a past point within the object's data retention period. |
|---|---|
| Fail-safe | A 7-day, non-queryable recovery period after time travel for permanent tables, usable only by Snowflake support. |
| Zero-copy clone | A metadata-only copy of a table, schema or database that shares micro-partitions with the source until either changes. |
| Stream | An object that tracks an offset on a table and exposes row-level changes since that offset, with change metadata columns. |
| Stream offset | The table version a stream has consumed up to; it advances only when the stream is read in a committed DML statement. |
| Task | A Snowflake object that runs SQL on a schedule or after a predecessor task, optionally gated by a WHEN condition. |
| Transient table | A table with at most 1 day of time travel and no fail-safe, used for re-creatable data to save storage. |
In two minutes
- Time travel lets you query (AT / BEFORE) or restore (CLONE … AT, UNDROP) data from within the retention period: default 1 day; up to 90 days on Enterprise edition for permanent tables.
- After time travel ends, permanent tables get 7 days of fail-safe — recoverable only by Snowflake support, not by your queries; transient and temporary tables have no fail-safe.
- A zero-copy clone copies metadata, not data; both objects share micro-partitions until either side changes, and only changed data costs new storage.
- A stream records an offset on a table and returns the net row changes since then, with METADATA$ACTION, METADATA$ISUPDATE and METADATA$ROW_ID.
- The stream's offset only advances when the stream is read inside a DML statement that commits; plain SELECTs don't consume it.
- Tasks run SQL on a schedule or after another task; WHEN SYSTEM$STREAM_HAS_DATA skips runs (and warehouse spend) when nothing changed.
- Retention costs storage: high-churn tables with long retention hold many old micro-partitions, and an unconsumed stream extends retention until it goes stale.
Test yourself
1. What is the default data retention (time travel) period for a Snowflake table?
- 7 days
- 1 day
- 90 days
- 0 days
Show the answer
1 day — Default DATA_RETENTION_TIME_IN_DAYS is 1. Enterprise edition can raise it to 90 for permanent tables; 7 days is fail-safe, a different thing.
2. Who can recover data from fail-safe?
- Any role with OWNERSHIP on the table
- ACCOUNTADMIN with an AT clause
- Only Snowflake support
- Nobody — fail-safe data is deleted immediately
Show the answer
Only Snowflake support — Fail-safe is a disaster-recovery window operated by Snowflake. It isn't queryable, and transient/temporary tables don't have it.
3. What makes a zero-copy clone 'zero-copy'?
- It copies data in compressed form
- It creates new metadata pointing at the same micro-partitions; storage is only used when either side changes
- It's a read-only view
- It streams data lazily from the source on each query, so it breaks if the source is dropped
Show the answer
It creates new metadata pointing at the same micro-partitions; storage is only used when either side changes — Cloning duplicates metadata only. The clone is fully writable and independent; diverging changes create new micro-partitions for that side alone.
4. An analyst runs SELECT * FROM rides_s (a stream) three times during debugging. What happens to the offset?
- It advances each time, so the second and third SELECT return nothing
- It advances after the third read
- It resets to the table's creation
- It doesn't move — only a committed DML statement reading the stream advances it
Show the answer
It doesn't move — only a committed DML statement reading the stream advances it — Plain queries are side-effect free. The offset moves only when the stream is consumed in a DML transaction that commits.
5. A row is updated in the source table. How does it appear in a standard stream (if it existed before the offset)?
- As a DELETE row and an INSERT row, both with METADATA$ISUPDATE = TRUE
- As one UPDATE row
- Not at all — streams only track inserts
- As two INSERT rows
Show the answer
As a DELETE row and an INSERT row, both with METADATA$ISUPDATE = TRUE — Streams represent an update as the old row (DELETE) and the new row (INSERT), flagged with ISUPDATE = TRUE. Append-only streams ignore updates and deletes.
6. You created a task with CREATE TASK … SCHEDULE = '5 MINUTE'. Nothing has run after an hour. Most likely why?
- The schedule syntax needs cron
- Tasks run only on Enterprise edition
- Tasks are created suspended; it needs ALTER TASK … RESUME
- The warehouse is too small
Show the answer
Tasks are created suspended; it needs ALTER TASK … RESUME — Every new task starts suspended. In a task graph, resume the children before the root.
There are 9 questions, 3 puzzles and 5 recall cards for this lesson in the app — the recall cards come back on later days, just before you would forget.
Start this lesson →