La conversion d’un modèle incrémentiel existant vers microbatch est généralement simple. Les modifications mécaniques sont directes : supprimer le bloc is_incremental(), ajouter la configuration event_time et batch_size, et laisser dbt gérer le filtrage. La partie plus difficile est de savoir quand la conversion est pertinente et de gérer la première exécution après la migration.
Quand la migration est pertinente
Tous les modèles incrémentiels ne bénéficient pas de microbatch. Avant de convertir, vérifiez que le modèle remplit ces critères :
-
Colonne horodatage claire : Le modèle a besoin d’une colonne qui définit proprement à quel moment chaque enregistrement appartient dans le temps. C’est ce qui devient
event_time. Les modèles qui mettent à jour des enregistrements sur des plages de temps arbitraires — comme SCD Type 2 ou des patterns CDC complexes — ne s’adaptent pas au modèle de batch. -
Granularité horaire ou plus grossière : Le
batch_sizeminimum de microbatch esthour. Si le modèle actuel traite des fenêtres inférieures à l’heure (intervalles de 15 minutes ou 5 minutes), microbatch ne fonctionnera pas. Voir la note sur les compromis pour les détails. -
Traitement borné dans le temps : La logique
is_incremental()actuelle doit déjà filtrer par une colonne temporelle. Si le filtre incrémentiel est basé sur une colonne non temporelle (comme un ID auto-incrémentiel ou un flag de statut), microbatch n’est pas la bonne stratégie. -
Valeur de backfill ou relance : Microbatch ajoute une surcharge (exécution séquentielle des batchs) en échange d’une relance par batch et d’un backfill intégré. Si le modèle ne tombe jamais en erreur et qu’il n’est jamais nécessaire de retraiter des plages de dates spécifiques, ce compromis n’en vaut pas la peine.
Côte à côte : avant et après
Voici un modèle incrémentiel traditionnel typique et son équivalent microbatch.
Incrémentiel traditionnel (delete+insert)
{{ config( materialized='incremental', incremental_strategy='delete+insert', unique_key='date_day') }}
SELECT event_id, user_id, event_occurred_at, event_name, event_propertiesFROM {{ ref('base__app__events') }}{% if is_incremental() %}WHERE date_day >= ( SELECT {{ dbt.dateadd("day", -3, "max(date_day)") }} FROM {{ this }}){% endif %}Équivalent microbatch
{{ config( materialized='incremental', incremental_strategy='microbatch', event_time='event_occurred_at', batch_size='day', lookback=3, begin='2020-01-01') }}
SELECT event_id, user_id, event_occurred_at, event_name, event_propertiesFROM {{ ref('base__app__events') }}Les différences :
- Bloc
is_incremental()supprimé : dbt gère le filtrage temporel automatiquement en fonction deevent_timeetbatch_size. event_timeajouté : Pointe vers la colonne horodatage qui définit les limites des batchs. Remplace la logique manuelleWHERE date_day >= ....lookbackremplace la fenêtre manuelle : Le paramètrelookback=3indique à dbt de retraiter les 3 batchs précédents, exactement comme le patterndateadd("day", -3, ...)dans l’original.- Date
beginajoutée : Requise pour microbatch. Définit la date la plus ancienne que dbt traitera lors d’un full build. unique_keysupprimé : Non requis pour la plupart des entrepôts. Sur BigQuery, microbatch utiliseinsert_overwriteen coulisses (remplacement de partition, pas de matching de lignes). Sur Snowflake, il utilisedelete+insert. Seul le microbatch PostgreSQL nécessiteunique_keycar il délègue au merge.
Migration étape par étape
1. Cartographier la logique existante
Avant de modifier le code, identifier :
- Quelle colonne est le filtre temporel ? C’est ce qui devient
event_time. C’est la colonne dans la clauseWHEREqui filtre les enregistrements par temps. - Quelle est la fenêtre de lookback actuelle ? Si 3 jours sont soustraits dans le bloc
is_incremental(), définirlookback=3. - Quelle granularité convient ? Si le traitement est quotidien, utiliser
batch_size='day'. Si le modèle tourne toutes les heures et traite la dernière heure, utiliserbatch_size='hour'. - Quelle est la date la plus ancienne dans la table ? C’est ce qui devient
begin. Vérifier viaSELECT MIN(event_time_column) FROM your_table.
2. Ajouter la configuration spécifique à l’entrepôt
Microbatch utilise des stratégies sous-jacentes différentes selon l’entrepôt. Certains nécessitent une configuration supplémentaire :
BigQuery nécessite partition_by correspondant à event_time :
{{ config( materialized='incremental', incremental_strategy='microbatch', partition_by={ "field": "event_occurred_at", "data_type": "timestamp", "granularity": "day" }, event_time='event_occurred_at', batch_size='day', begin='2020-01-01') }}La granularité de partition_by doit correspondre au batch_size. Les incompatibilités ne cassent pas le modèle mais réduisent l’efficacité — une partition mensuelle avec des batchs quotidiens signifie que plusieurs batchs écrivent dans la même partition, perdant le bénéfice du remplacement atomique de partition.
Snowflake et Databricks ne nécessitent pas de configuration supplémentaire. Les stratégies sous-jacentes (delete+insert et replace_where respectivement) fonctionnent sans paramètres additionnels.
PostgreSQL nécessite unique_key car microbatch délègue au merge :
{{ config( materialized='incremental', incremental_strategy='microbatch', unique_key='event_id', event_time='event_occurred_at', batch_size='day', begin='2020-01-01') }}3. Configurer event_time en amont
Si les modèles en amont (ceux référencés via ref()) ont une colonne horodatage, configurez également event_time sur eux. Cela active le filtrage automatique en amont — dbt filtrera les tables source pour correspondre à la fenêtre du batch courant, évitant les scans de tables complètes.
models: - name: base__app__events config: event_time: event_occurred_atCe n’est pas requis pour la migration, mais c’est une optimisation significative des performances. Sans cela, chaque batch lit la table en amont complète.
4. Supprimer la logique redondante
Supprimez entièrement le bloc is_incremental(). Tout filtrage temporel manuel, calcul de lookback ou logique conditionnelle liée au traitement incrémentiel est désormais géré par la configuration microbatch.
Supprimez également :
- Les calculs de lookback
dateadd/DATE_SUBmanuels - Les références à
{{ this }}pour déterminer la date maximale traitée - Toute configuration
unique_key(sauf sur PostgreSQL) - Les overrides de variables de backfill personnalisés (microbatch a un backfill intégré)
5. Valider avec des tests unitaires
Avant le déploiement, validez que la version microbatch produit les mêmes résultats que la version traditionnelle. Exécutez les deux en parallèle et comparez les sorties avec des tests unitaires ou des requêtes de comparaison manuelles :
-- Comparer les comptages de lignes par jourSELECT DATE(event_occurred_at) AS event_date, COUNT(*) AS row_countFROM traditional_modelGROUP BY 1
EXCEPT DISTINCT
SELECT DATE(event_occurred_at) AS event_date, COUNT(*) AS row_countFROM microbatch_modelGROUP BY 1;Si les résultats divergent, les causes les plus courantes sont :
- Différences de fuseau horaire : Microbatch utilise UTC pour les limites de batch. Si le modèle original utilisait l’heure locale, les enregistrements proches de minuit tomberont dans des batchs différents.
- Incompatibilité de lookback : Vérifier que
lookbackcorrespond exactement à la taille de fenêtre originale. - Changements de déduplication : Si le modèle original s’appuyait sur
unique_keypour la déduplication lors du merge, et que le nouveau microbatch délègue àinsert_overwrite(BigQuery), une déduplication explicite dans le SELECT peut être nécessaire.
Gérer la première exécution
Lors de la première exécution après la conversion vers microbatch, deux options s’offrent à vous :
Option A : Full refresh
L’approche la plus simple. Exécutez dbt run --full-refresh --select your_model pour reconstruire la table de zéro en utilisant la logique microbatch. dbt traite chaque batch de begin à maintenant, séquentiellement.
Pour les tables petites à moyennes, c’est correct. Pour les très grandes tables, c’est lent — une table avec 5 ans de données quotidiennes signifie 1 825 requêtes de batch séquentielles. Envisagez l’option B.
Option B : Reconstruction bornée par morceaux
Utilisez --event-time-start et --event-time-end pour reconstruire par morceaux gérables :
# Reconstruire les données 2024dbt run --full-refresh --select int__sessions_aggregated \ --event-time-start "2024-01-01" --event-time-end "2024-07-01"
dbt run --full-refresh --select int__sessions_aggregated \ --event-time-start "2024-07-01" --event-time-end "2025-01-01"C’est particulièrement utile sur BigQuery où le coût de calcul de chaque batch est proportionnel aux données scannées. Le traitement par morceaux plus petits maintient les coûts de requêtes individuelles à un niveau gérable et permet de relancer des morceaux spécifiques en cas d’échec.
Option C : Conserver les données existantes
Si la structure de table existante est compatible (mêmes colonnes, même partitionnement), un full refresh n’est peut-être pas nécessaire du tout. La prochaine exécution incrémentielle utilisera la logique microbatch pour traiter les nouveaux batchs depuis l’endroit où la table s’est arrêtée. dbt détermine le point de « dernier traitement » depuis les données existantes dans la table.
Cela fonctionne mieux quand :
- La table est déjà partitionnée par la même colonne utilisée comme
event_time - Aucune logique de transformation n’a changé, seulement la stratégie incrémentielle
- On est à l’aise avec les données historiques existantes telles qu’elles sont
Pièges courants de migration
Oublier begin : Sans begin, dbt ne sait pas jusqu’où remonter lors d’un full refresh. Le modèle génère une erreur.
Surprises aux limites UTC : Le modèle original peut avoir utilisé des limites de batch en heure locale (minuit heure de l’Est, minuit CET). Microbatch utilise exclusivement UTC. Les enregistrements proches de la fin de la journée locale tomberont dans des batchs différents qu’avant. Si cela importe pour le reporting, il faut convertir les horodatages en UTC avant de les définir comme event_time.
Exigence unique_key PostgreSQL : Tous les autres entrepôts fonctionnent sans unique_key pour microbatch, mais PostgreSQL en a besoin car microbatch délègue au merge. L’oublier cause des erreurs, pas des échecs silencieux.
full_refresh=false trop agressif : Définir full_refresh=false immédiatement après la migration empêche de faire facilement une reconstruction complète si quelque chose se passe mal. Attendez d’avoir validé le comportement microbatch avant d’ajouter cette protection.