Dans les articles précédents, on a posé les bases :
- L’architecture de Snowflake (storage / compute / cloud services)
- Les types de tables
- Les types de vues
- Les stages
- Les file formats
La question d'après, c'est :
Comment savoir ce qui a changé dans une table, suivre ces changements et ne charger que le delta ( chargement incrémental ) ?
C'est exactement ce que les streams Snowflake viennent résoudre.
C'est quoi concrètement un stream dans Snowflake ?
Un stream est un objet Snowflake, pareil qu'une table ou une vue. Sa mission, c'est de répondre à une question simple : “qu'est-ce qui a changé dans cette table ou cette vue depuis la dernière fois que je l'ai consommé ?” ce qui permet de faire du delta, et de l'incremental load facilement.
Comme on l’a vu dans les articles d’avant, Snowflake garde l’historique des données avec le Time Travel et du change tracking. Un stream vient juste s’appuyer dessus et donc au moment où on le crée, il prend un point de départ, puis à chaque fois qu’on le lit, il ne renvoie que les lignes qui ont changé (ajout, modification, suppression) depuis la dernière fois.
Exemple de la création d'un stream
Rien ne vaut un exemple pour comprendre le concept, on commence par créer une table members.
CREATE OR REPLACE TABLE members (
id NUMBER,
name STRING,
age NUMBER
);
INSERT INTO members VALUES (1, 'Titi', 30);
INSERT INTO members VALUES (2, 'Bob', 25);
On crée un stream dessus :
CREATE OR REPLACE STREAM members_stream
ON TABLE members;
On fait quelques opérations :
UPDATE members SET age = 31 WHERE id = 1;
DELETE FROM members WHERE id = 2;
Si tu fais :
SELECT * FROM members;
tu peux voir l'état courant de la table.

Si tu fais :
SELECT * FROM members_stream;
tu peux voir les changements depuis la création du stream, plus quelques colonnes techniques qui expliquent ce qui s'est passé.

NB : dans un stream, un UPDATE est représenté comme un DELETE suivi d'un INSERT.
Les colonnes METADATA$…
Quand tu interroges un stream, Snowflake rajoute trois colonnes :
METADATA$ACTIONte dit si la ligne correspond à unINSERTou unDELETE.METADATA$ISUPDATEest à TRUE quand cette ligne fait partie d'unUPDATE(qui est représenté comme unDELETE+INSERT).METADATA$ROW_IDest un identifiant unique par ligne, utile si tu veux suivre la même ligne au fil du temps et voir toutes les modifications.
Les principaux types de streams
Snowflake propose trois types de streams. Le principe reste le même, ce qui change c'est ce qu'ils remontent.
Standard stream
C'est le type par défaut. Il suit tout les INSERT, UPDATE (représenté en DELETE + INSERT) et DELETE.
C'est parfait pour faire du CDC.
CREATE OR REPLACE STREAM members_stream
ON TABLE members;
Append-only stream
L'append-only stream ne renvoie que les nouvelles lignes (uniquement les inserts).
Les updates et deletes ne remontent pas.
C'est très bien pour des tables qui ne font que grossir (logs, events) ou quand tu n'as besoin que des nouvelles insertion.
CREATE OR REPLACE STREAM members_stream_append
ON TABLE members
APPEND_ONLY = TRUE;
Insert-only stream
Insert-only stream est surtout là pour les external tables (et les tables Iceberg externes).
L'idée est la même que pour l'append-only, c'est quand tu veux voir quelles nouvelles lignes sont arrivées dans ton data lake depuis la dernière fois.
CREATE OR REPLACE STREAM ext_orders_stream
ON EXTERNAL TABLE ext_orders
INSERT_ONLY = TRUE;
Comment consommer un stream dans un pipeline ?
Prenons un cas très simple, donc on a une table members où arrivent les nouvelles lignes, et on veut garder une autre table members_dim à jour avec ces données. L'idée donc est juste de répercuter les nouvelles lignes dans members_dim...
On va créer un stream append-only qui point sur la table members :
CREATE OR REPLACE STREAM members_stream_append
ON TABLE members
APPEND_ONLY = TRUE;
Et on va créer la nouvelle table cible members_dim :
CREATE OR REPLACE TABLE members_dim (
id NUMBER,
name STRING,
age NUMBER
);
Pour synchroniser members_dim avec uniquement les nouvelles lignes de la table members , on peut faire un MERGE très basique :
MERGE INTO members_dim d
USING members_stream_append s
ON d.id = s.id
WHEN MATCHED THEN
UPDATE SET
d.name = s.name,
d.age = s.age
WHEN NOT MATCHED THEN
INSERT (id, name, age)
VALUES (s.id, s.name, s.age);
Si ensuite on veut gérer aussi les deletes et les updates, là on passe par un standard stream et on s'appuie davantage sur les colonnes METADATA$ACTION et METADATA$ISUPDATE.
| Type | Capture | Cas d'usage | Sur quel objet ? |
|---|---|---|---|
| Standard | INSERT, UPDATE, DELETE | CDC complet, propagation de changements vers un mart | Table, vue |
| Append-only | INSERT uniquement | Logs, events, ingestion de tables qui ne font que grossir | Table, vue |
| Insert-only | Nouveaux fichiers détectés | External tables, Iceberg externes | External table, Iceberg externe |
La règle simple : tu veux tout suivre => standard. Tu veux juste les nouvelles lignes => append-only. Tu es sur une external table => insert-only.
Comment choisir son type de stream ?
C'est très simple :
- Tu veux tout suivre (insert / update / delete) → standard stream.
- Tu veux suivre que les nouvelles lignes → append-only stream (ou insert-only si c’est une external table).
Cet article vient compléter la petite série sur Snowflake. Si on résume ce qu’on a vu jusqu’ici :
- Architure pour comprendre comment snowflake fonctionne
- les stages répondent à la question “où sont les fichiers ?”
- les file formats expliquent “comment les lire”
- les tables et les vues sont l’endroit où la donnée vit et est exposée
- les streams nous disent ce qui a changé entre deux exécutions.
Dans le prochain article, on va s'attaquer aux Tasks qui complètent les streams pour automatiser le rafraîchissement.
Aller plus loin : préparer la SnowPro Core
Les streams sont un sujet récurrent à l'examen SnowPro Core, surtout les colonnes METADATA$ACTION, METADATA$ISUPDATE et METADATA$ROW_ID. La différence entre standard, append-only et insert-only est aussi régulièrement testée. Sur DataCertification.fr, le module SnowPro Core couvre ces sujets avec 700 questions scenario-based au format de l'examen.
👉 Préparer la SnowPro Core sur DataCertification.fr
Pour aller plus loin sur Snowflake en général, j'ai regroupé tous mes articles dans un parcours complet.
👉 Accéder à la Formation Snowflake
Tu veux que je t'accompagne sur ton projet data (Snowflake, pipelines incrémentaux, CDC, modélisation, dbt) ?
👉 Réserver un appel de 30 minutes
Questions
C'est quoi un stream dans Snowflake ?
Un stream Snowflake est un objet qui suit les changements (INSERT, UPDATE, DELETE) sur une table ou une vue depuis la dernière fois qu'il a été consommé. Il s'appuie sur le mécanisme de Time Travel et le change tracking de Snowflake. À chaque création, le stream prend un point de départ, et à chaque lecture il renvoie uniquement les lignes qui ont changé depuis.
Quelle différence entre standard, append-only et insert-only stream ?
Le stream standard capture tous les changements (INSERT, UPDATE, DELETE) et c'est le choix par défaut pour le CDC complet. Le stream append-only ne capture que les INSERT, idéal pour les tables de logs ou d'events qui ne font que grossir. Le stream insert-only est spécifique aux external tables et tables Iceberg externes pour détecter les nouveaux fichiers arrivés depuis la dernière exécution.
À quoi sert METADATA$ACTION dans un stream Snowflake ?
METADATA$ACTION est une colonne automatique ajoutée par Snowflake aux streams. Elle indique si la ligne correspond à un INSERT ou un DELETE. Pour les UPDATE, Snowflake les représente comme un DELETE suivi d'un INSERT, donc tu vois deux lignes : une avec METADATA$ACTION = 'DELETE' (ancienne valeur) et une avec METADATA$ACTION = 'INSERT' (nouvelle valeur), toutes les deux avec METADATA$ISUPDATE = TRUE.
Comment Snowflake représente-t-il un UPDATE dans un stream ?
Snowflake représente un UPDATE comme deux lignes dans le stream donc une ligne avec METADATA$ACTION = 'DELETE' qui contient les anciennes valeurs, et une ligne avec METADATA$ACTION = 'INSERT' qui contient les nouvelles valeurs. Les deux ont METADATA$ISUPDATE = TRUE pour signaler qu'elles font partie d'un UPDATE et pas d'un vrai INSERT ou DELETE séparé.
Comment consommer un stream Snowflake dans un pipeline ?
Tu consommes un stream en l'utilisant dans une instruction DML (MERGE, INSERT, UPDATE, DELETE) à l'intérieur d'une transaction. Le plus courant est un MERGE qui prend le stream comme source et matche sur la clé primaire. Une fois la transaction commitée, le stream se réinitialise et ne renverra plus les lignes déjà consommées. Pour automatiser, on combine généralement un stream avec une Task qui rejoue le MERGE selon un schedule.
Un stream consomme-t-il du stockage dans Snowflake ?
Non, un stream ne stocke pas les données lui-même. Il s'appuie sur les métadonnées et l'historique de Time Travel de la table source. Snowflake garde juste un offset qui indique où le stream en est dans la timeline des changements. C'est pour ça que les streams sont quasi gratuits en stockage. Mais attention, si tu ne consommes pas un stream pendant longtemps, la table source doit conserver son historique Time Travel correspondant.
Comment vérifier qu'un stream contient des données à traiter ?
Utilise la fonction SYSTEM$STREAM_HAS_DATA('nom_du_stream') qui retourne TRUE si le stream contient des changements non consommés. C'est très utilisé dans la clause WHEN d'une Task pour éviter de réveiller le warehouse quand il n'y a rien à traiter : WHEN SYSTEM$STREAM_HAS_DATA('mon_stream'). Tu peux aussi simplement faire SELECT COUNT(*) FROM mon_stream pour avoir le détail.
Stream + Task ou Dynamic Tables : que choisir ?
Streams + Tasks offrent plus de contrôle car tu écris ta propre logique MERGE, tu choisis le moment d'exécution, tu peux orchestrer des dépendances complexes. Dynamic Tables sont plus simples puisque tu décris le résultat final avec un SELECT et Snowflake gère l'incrémental automatiquement avec un TARGET_LAG. Choisis Dynamic Tables si ton pipeline est simple, choisis Streams + Tasks si tu as besoin de logique custom ou d'intégrations externes.
Peut-on créer un stream sur une vue Snowflake ?
Oui. On peut créer un stream sur une vue standard, et Snowflake suit les changements à travers la vue jusqu'aux tables sous-jacentes. C'est utile quand tu veux exposer un stream filtré ou joint sans dupliquer la logique. Attention, les vues secure et les vues matérialisées ne supportent pas les streams. Pour les external tables et Iceberg externes, il faut utiliser un stream INSERT_ONLY.
