AccueilBlogTest technique dbt snapshots et SCD : historiser les changements
Guide recrutement data

Test technique dbt snapshots et SCD : historiser les changements

Historiser les changements de données (Slowly Changing Dimensions) est un sujet classique en entretien. dbt snapshots offrent une solution élégante mais qui nécessite une vraie compréhension.

Data Builder·Juin 2025·6 min de lecture·Analytics Engineer · Data Engineer
Sommaire
  1. Types de SCD
  2. Snapshots dbt
  3. Stratégie timestamp
  4. Stratégie check
  5. Gestion des suppressions
  6. Consommer les snapshots
  7. Grille

1Types de SCD : lequel choisir

Question discriminante

Quelle est la différence entre SCD1, SCD2 et SCD3 ? Quand utilisez-vous SCD2 ?

  • SCD Type 1 — overwrite. La valeur actuelle écrase l'ancienne. Pas d'historique. Simple, idéal pour les corrections d'erreurs
  • SCD Type 2 — nouvelle ligne pour chaque changement. Conserve tout l'historique avec des colonnes valid_from/valid_to/is_current. Le plus courant en data warehousing
  • SCD Type 3 — colonne supplémentaire pour la valeur précédente. Limite : ne conserve que N versions. Rare en pratique
  • Quand SCD2 — analyse des comportements dans le temps (comment le segment client a évolué), attribution correcte (le prix au moment de l'achat), conformité réglementaire
  • Coût SCD2 — les jointures avec une table SCD2 nécessitent de filtrer sur is_current=true ou sur la plage de dates. Ajoute de la complexité aux requêtes
TypeHistoriqueComplexitéCas d'usage
SCD1AucunSimpleDonnées de référence, corrections
SCD2CompletÉlevéeDimensions clients, produits, géographie
SCD3Partiel (N versions)MoyenneRare

2Snapshots dbt : SCD2 automatique

Question discriminante

Qu'est-ce qu'un snapshot dbt ? Comment le configurez-vous ?

-- snapshots/customers_snapshot.sql {% snapshot customers_snapshot %} {{ config( target_schema='snapshots', unique_key='customer_id', strategy='timestamp', updated_at='updated_at', invalidate_hard_deletes=True ) }} SELECT customer_id, email, plan, segment, country, updated_at FROM {{ source('crm', 'customers') }} {% endsnapshot %} -- Colonnes ajoutées automatiquement par dbt : -- dbt_scd_id : clé primaire du snapshot (hash) -- dbt_valid_from : date de début de validité -- dbt_valid_to : date de fin (NULL = enregistrement actuel) -- dbt_updated_at : timestamp de la dernière mise à jour
  • dbt snapshot run — crée le snapshot si inexistant, sinon détecte les changements et insère de nouvelles lignes
  • target_schema — stocker les snapshots dans un schema dédié, séparé des modèles marts
  • unique_key — identifiant naturel de l'entité. Plusieurs colonnes possibles : unique_key=['id', 'source']

3Stratégie timestamp vs check

Question discriminante

Quelle est la différence entre la stratégie timestamp et check dans les snapshots dbt ?

-- Stratégie TIMESTAMP : recommandée -- Utilise une colonne updated_at pour détecter les changements -- Rapide : compare juste un timestamp {{ config( strategy='timestamp', updated_at='updated_at' -- colonne de la source ) }} -- Stratégie CHECK : quand pas d'updated_at -- Compare la valeur de colonnes spécifiées -- Plus lente : hash des colonnes à chaque run {{ config( strategy='check', check_cols=['plan', 'segment', 'country'] -- ou check_cols='all' pour toutes les colonnes ) }}
  • Timestamp — nécessite une colonne updated_at fiable dans la source. Rapide et scalable
  • Check — dbt compare un hash des colonnes spécifiées. Plus lent sur grandes tables mais fonctionne sans updated_at
  • Piège timestamp — si la source ne met pas updated_at à jour correctement, des changements seront manqués

4Gérer les suppressions dans les snapshots

Question discriminante

Que se passe-t-il quand une ligne est supprimée dans la source ? Comment le gérer ?

-- Avec invalidate_hard_deletes=True -- dbt marque les enregistrements supprimés avec dbt_valid_to = current_timestamp -- La colonne dbt_is_deleted est ajoutée automatiquement -- Requête pour analyser les suppressions SELECT customer_id, email, dbt_valid_from, dbt_valid_to, CASE WHEN dbt_valid_to IS NULL THEN 'actif' ELSE 'inactif/supprimé' END AS statut FROM {{ ref('customers_snapshot') }} WHERE customer_id = 12345 ORDER BY dbt_valid_from;
  • invalidate_hard_deletes=True — recommandé. dbt détecte les suppressions et ferme la ligne courante
  • Sans cette option — les enregistrements supprimés restent ouverts (dbt_valid_to = NULL) indéfiniment
  • Soft deletes — si la source a une colonne is_deleted, filtrer dans la requête du snapshot : WHERE is_deleted = false

5Consommer les snapshots dans les modèles dbt

Question discriminante

Comment interrogez-vous un snapshot pour obtenir l'état actuel vs l'état historique ?

-- État ACTUEL : enregistrements dont dbt_valid_to est NULL -- models/marts/dim_customers.sql SELECT customer_id, email, plan, segment, dbt_valid_from AS snapshot_date FROM {{ ref('customers_snapshot') }} WHERE dbt_valid_to IS NULL -- enregistrements actifs uniquement -- État HISTORIQUE : quel segment avait ce client au moment de sa commande ? -- Utile pour l'attribution correcte SELECT o.order_id, o.customer_id, o.amount, o.order_date, c.segment AS segment_at_order_time -- segment du client AU MOMENT de la commande FROM {{ ref('fct_orders') }} o JOIN {{ ref('customers_snapshot') }} c ON o.customer_id = c.customer_id AND o.order_date BETWEEN c.dbt_valid_from AND COALESCE(c.dbt_valid_to, CURRENT_DATE)
  • SCD Type 2 en pratique - la complexite est dans les jointures aval. Toujours joindre avec la condition temporelle : order_date BETWEEN dbt_valid_from AND COALESCE(dbt_valid_to, CURRENT_DATE)
  • Piege timestamp - si la source ne met pas updated_at a jour correctement, des changements seront manques. Verifier la fiabilite de la colonne avant de choisir la strategie timestamp
  • invalidate_hard_deletes - recommande. dbt detecte les suppressions et ferme la ligne courante avec dbt_valid_to = current_timestamp
  • Performance - les snapshots sur des tables source de plusieurs millions de lignes peuvent etre lents avec la strategie check. Privilegier timestamp quand possible
  • Snapshot testing - tester que dbt_valid_to IS NULL pour les enregistrements actifs, dbt_valid_from < dbt_valid_to pour les historiques, pas de chevauchement de periodes
-- Consommer un snapshot dbt correctement -- Etat ACTUEL : enregistrements dont dbt_valid_to est NULL SELECT customer_id, email, plan, segment, dbt_valid_from AS depuis FROM {{ ref('customers_snapshot') }} WHERE dbt_valid_to IS NULL; -- Etat HISTORIQUE : quel segment avait ce client au moment de sa commande ? -- Indispensable pour l attribution correcte SELECT o.order_id, o.amount, o.order_date, c.segment AS segment_au_moment_de_la_commande FROM {{ ref('fct_orders') }} o JOIN {{ ref('customers_snapshot') }} c ON o.customer_id = c.customer_id AND o.order_date BETWEEN c.dbt_valid_from AND COALESCE(c.dbt_valid_to, CURRENT_DATE); -- Analyser l evolution d un client SELECT customer_id, plan, segment, dbt_valid_from, dbt_valid_to FROM {{ ref('customers_snapshot') }} WHERE customer_id = 'CUST-42' ORDER BY dbt_valid_from;
  • Jointure temporelle - joindre une table de faits avec un SCD2 via la condition : event_date BETWEEN dbt_valid_from AND COALESCE(dbt_valid_to, CURRENT_DATE)
  • Performance snapshot - les snapshots sur des tables source de plusieurs millions de lignes peuvent etre lents avec la strategie check. Privilegier timestamp quand disponible
  • Snapshot testing - tester que dbt_valid_to IS NULL pour les enregistrements actifs, que dbt_valid_from est anterieur a dbt_valid_to pour les historiques

6Grille par niveau

NiveauMaîtriseSignal GONO-GO
ConfirméSCD1 vs SCD2, configuration snapshot dbt, stratégie timestampExplique les 3 types de SCD, a configuré un snapshot avec stratégie timestamp, sait requêter l'état actuelNe sait pas ce qu'est un SCD2, n'a jamais utilisé les snapshots dbt
SeniorGestion des suppressions, jointures historiques, check vs timestamp, performanceGère les hard deletes, fait des jointures temporelles pour l'attribution historique, connaît les limites de performanceNe sait pas comment joindre une table de faits avec un SCD2 au bon moment

Vous recrutez un Analytics Engineer ?

Premier entretien gratuit. Rapport GO/NO-GO sous 48h.