Snowflake

Streams: Change Data Capture on Tables

Track row-level changes (inserts, updates, deletes) on a table for incremental processing.

A stream tells you what changed in a table since you last looked. It is how incremental pipelines avoid reprocessing everything.

A stream is like a bookmark in a constantly-updated document — querying it shows you everything that changed since your bookmark, and only moving the bookmark forward (by actually processing those changes) marks them as handled.

Key Concepts

1
    CREATE STREAM orders_stream ON TABLE orders;
2
It stores no data. A stream is a bookmark — an offset into the table's version history. When you query it, Snowflake computes the difference between the table now and the table at that offset, using the same retained micro-partitions that power Time Travel.
3
So creating a stream costs nothing and takes no storage.
4
Three metadata columns come back with each row.
    METADATA$ACTION      INSERT or DELETE
    METADATA$ISUPDATE    TRUE if this is half of an update
    METADATA$ROW_ID      a stable id for the row
5
An update appears as a DELETE and an INSERT pair, both with ISUPDATE = TRUE. That is how you tell a real delete from the removal half of an update — a distinction that quietly breaks merge logic when missed.
ISUPDATE = TRUE
6
Reading does not consume it. This is the property that makes streams usable:
7
    SELECT * FROM orders_stream;       -- inspect freely, offset unchanged
    INSERT INTO target
      SELECT * FROM orders_stream;     -- offset advances
8
The offset only moves when the stream is used inside a DML statement, and only if that statement commits. So you can look at what is pending as often as you like, and a failed job leaves the changes waiting rather than losing them.
9
The usual pattern is a stream plus a task plus a merge.
    MERGE INTO target t USING orders_stream s ON t.id = s.id
      WHEN MATCHED AND s.METADATA$ACTION = 'DELETE' THEN DELETE
      WHEN MATCHED THEN UPDATE SET ...
      WHEN NOT MATCHED THEN INSERT ...
10
Staleness is the trap. A stream can only compute its delta while the retained versions it needs still exist. That window is the source table's data retention period.
11
    retention 1 day, stream not consumed for 2 days
    -> stream is stale, and its pending changes are gone
12
A stale stream cannot be repaired. It must be recreated, and whatever it had not yet delivered must be recovered another way — usually a full reload.
13
So a pipeline that pauses over a long weekend can lose data silently. Check SYSTEM$STREAM_HAS_DATA and the stream's STALE_AFTER in monitoring, and give tables feeding critical streams a retention period comfortably longer than your worst outage.
SYSTEM$STREAM_HAS_DATASTALE_AFTER
14
Several streams on one table are independent. Each has its own offset, so two consumers can read the same changes without interfering — which is how one source feeds several downstream pipelines.
15
What the interviewer is probing.1. "What does a stream actually store?" Probing: the mechanism. Stalls: "The changed rows." Moves up: an offset — the changes are derived from the table's versions, so the stream itself is metadata, not a copy.
16
2. "When does the offset advance?" Probing: the critical detail. Stalls: "When you read it." Moves up: when the stream is consumed inside a DML statement that commits — a plain SELECT does not advance it.
17
3. "What happens if a stream is not consumed?" Probing: the hazard. Stalls: "Nothing." Moves up: it becomes stale once the offset falls outside the retention window, and then it must be recreated with the changes lost.
18
4. "What are the three stream types?" Probing: the breadth. Stalls: "One type." Moves up: standard showing net changes, append-only which is cheaper for inserts, and insert-only for external tables.