AccueilBlogTest technique dbt modèles incrémentaux : stratégies et optimisation
Guide recrutement data

Test technique dbt modèles incrémentaux : stratégies et optimisation

Les modèles incrémentaux dbt sont le levier le plus puissant pour réduire les coûts et le temps de traitement. Mal configurés, ils produisent des données incorrectes. En entretien, on évalue la maîtrise des stratégies.

Data Builder·Juin 2025·7 min de lecture·Analytics Engineer
Sommaire
  1. Pourquoi les modèles incrémentaux
  2. Les 4 stratégies
  3. Strategy merge en détail
  4. Late-arriving data
  5. Full refresh et pièges
  6. Incrémental sur Snowflake
  7. Grille

1Pourquoi les modèles incrémentaux

Question discriminante

Quel problème les modèles incrémentaux dbt résolvent-ils ?

  • Problème — reconstruire entièrement une table de 1 milliard de lignes à chaque run dbt coûte cher en temps et en compute
  • Solution — ne traiter que les nouvelles lignes ou les lignes modifiées depuis le dernier run
  • Exemple — table fct_events : 500M lignes historiques. Chaque jour, 1M nouvelles lignes arrivent. Traiter 1M au lieu de 501M = 500x moins de compute
  • Risque — mal configuré, un modèle incrémental peut rater des lignes ou créer des doublons

2Les 4 stratégies incrémentales

Question discriminante

Quelles sont les différentes stratégies dbt pour les modèles incrémentaux ?

-- Strategy 1 : append (par défaut) -- Ajoute les nouvelles lignes, ne modifie pas les existantes {{ config(materialized='incremental') }} SELECT * FROM {{ ref('stg_events') }} {% if is_incremental() %} WHERE event_date > (SELECT MAX(event_date) FROM {{ this }}) {% endif %} -- Strategy 2 : merge (upsert) -- INSERT de nouvelles lignes + UPDATE des existantes {{ config( materialized='incremental', unique_key='order_id', incremental_strategy='merge' ) }} SELECT * FROM {{ ref('stg_orders') }} {% if is_incremental() %} WHERE updated_at > (SELECT MAX(updated_at) FROM {{ this }}) {% endif %} -- Strategy 3 : delete+insert -- Supprime les lignes de la fenetre et reinsere {{ config( materialized='incremental', unique_key=['order_id', 'date'], incremental_strategy='delete+insert' ) }}

3Strategy merge : quand et comment

Question discriminante

Quand utilisez-vous merge plutôt qu append ? Quel est le risque si unique_key est mal défini ?

  • Append — pour les données immuables (events, logs). Une ligne créée ne change jamais
  • Merge — pour les données qui changent (statut commande, profil client). Nécessite un unique_key
  • Risque unique_key incorrect — si plusieurs lignes ont la même clé, le merge garde une seule de manière arbitraire. Perte de données silencieuse
  • Composite key — souvent nécessaire : unique_key=['order_id', 'date'] si les données sont partitionnées par date

4Gérer les late-arriving data

Question discriminante

Qu est-ce que le late-arriving data ? Comment le gérez-vous dans un modèle incrémental ?

-- Problème : des événements du passé arrivent en retard -- Ex : un mobile en mode offline synchronise des events datant de 3 jours -- Solution : reprocesser une fenetre glissante de N jours {{ config( materialized='incremental', unique_key='event_id' ) }} SELECT * FROM {{ ref('stg_events') }} {% if is_incremental() %} -- Reprocesser les 3 derniers jours pour capturer les retardataires WHERE event_date >= ( SELECT DATEADD('day', -3, MAX(event_date)) FROM {{ this }} ) {% endif %}
  • Late-arriving data — données qui arrivent dans le pipeline après la date attendue
  • Fenetre glissante — reprocesser les N derniers jours plutôt que seulement depuis le MAX. Plus coûteux mais correct

5Full refresh : quand l utiliser

Question discriminante

Dans quels cas forcez-vous un full refresh sur un modèle incrémental ?

# Forcer un full refresh manuellement dbt run --full-refresh --select fct_orders # Cas où le full refresh est nécessaire : # 1. Changement de logique qui affecte l historique # 2. Ajout d une nouvelle colonne calculée # 3. Bug découvert sur les données passées # 4. Migration de stratégie (append -> merge) # Configuration : interdire le full refresh en production {{ config( materialized='incremental', full_refresh=false # bloque dbt run --full-refresh sur cette table ) }}
  • Bloquer le full refresh — sur les très grandes tables (TB+), un full refresh accidentel peut coûter très cher
  • Process de migration — pour les changements historiques, utiliser un backfill contrôlé par tranches de dates

6Optimisation incrémentale sur Snowflake

Question discriminante

Comment optimisez-vous les performances d un modèle dbt incrémental sur Snowflake ?

{{ config( materialized='incremental', unique_key='order_id', incremental_strategy='merge', cluster_by=['order_date', 'region'], # clustering sur Snowflake on_schema_change='append_new_columns', snowflake_warehouse='TRANSFORM_WH_S', merge_exclude_columns=['created_at'] # ne pas updater created_at ) }}
  • cluster_by — pré-trier les données pour que le merge soit plus rapide sur les grandes tables
  • merge_exclude_columns — éviter d écraser des colonnes qui ne doivent pas changer (created_at, inserted_at)
  • on_schema_change — append_new_columns ajoute les nouvelles colonnes sans full refresh
-- dbt incremental : les strategies {{ config( materialized='incremental', unique_key='order_id', incremental_strategy='merge', -- merge, append, delete+insert, insert_overwrite on_schema_change='sync_all_columns' -- gerer les changements de schema ) }} SELECT order_id, customer_id, amount, status, updated_at FROM {{ source('raw', 'orders') }} {% if is_incremental() %} WHERE updated_at > (SELECT MAX(updated_at) FROM {{ this }}) -- Pour Snowflake : WHERE updated_at > (SELECT DATEADD('day',-1,MAX(updated_at)) FROM {{ this }}) -- Safety window de 1 jour pour les retards de replication {% endif %} -- Verifier la fraicheur apres un run -- SELECT MAX(updated_at) FROM {{ this }} -- doit etre proche de NOW()
  • Safety window - toujours inclure un overlap (1-2h ou 1j) dans le filtre incremental pour capturer les donnees en retard de la source. Ne pas filtrer exactement sur MAX(updated_at)
  • Strategie merge vs append - merge : upsert, necessite une unique_key. append : ajoute uniquement les nouvelles lignes (plus rapide mais risque de doublons si rerun). delete+insert : supprime la partition puis reinsere
  • on_schema_change - sync_all_columns ajoute les nouvelles colonnes automatiquement. fail (defaut) : bloquer si le schema change. Choisir selon la maturite de la source
  • Full refresh force - dbt run --full-refresh recrée la table completement. A utiliser apres un changement de logique majeur ou pour corriger des donnees historiques
  • Partition pruning avec incremental - sur BigQuery/Snowflake, filtrer sur la colonne de partition dans la condition incrementale. Evite de scanner toute la table source

7Grille par niveau

NiveauMaitriseSignal GONO-GO
ConfirméStratégie append et merge, is_incremental(), unique_keyA configuré un modèle merge avec unique_key, comprend is_incremental()Ne sait pas ce qu est un modèle incrémental dbt
SeniorLate-arriving data, full refresh strategy, optimisation warehouseGère les late-arriving data avec fenêtre glissante, bloque le full refresh sur les grandes tablesNe sait pas ce qu est le late-arriving data

Vous recrutez un Analytics Engineer dbt ?

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