ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Filtrage automatique en amont avec Microbatch

Comment la stratégie microbatch de dbt filtre automatiquement les modèles en amont par event_time, réduisant les scans de tables complètes — et quand désactiver cela avec .render().

Planté
dbtincremental processingcost optimization

L’une des fonctionnalités les plus utiles de microbatch ne reçoit pas assez d’attention : le filtrage automatique en amont. Quand un modèle microbatch référence un autre modèle via ref(), dbt vérifie si ce modèle en amont a également event_time configuré. Si c’est le cas, dbt filtre automatiquement les données en amont pour correspondre à la fenêtre temporelle du batch courant. Pas de SQL supplémentaire, pas de clauses WHERE manuelles.

Cela importe pour le coût et les performances. Sans filtrage automatique, chaque batch lirait la table en amont entière puis écarterait tout ce qui se trouve en dehors de la fenêtre du batch. Sur une grande table d’événements, cela représente un scan complet de table par batch — multiplié par le nombre de batchs traités.

Comment ça fonctionne

Supposons un modèle microbatch qui agrège des pages vues en sessions :

{{ config(
materialized='incremental',
incremental_strategy='microbatch',
event_time='session__started_at',
batch_size='day',
lookback=3,
begin='2023-01-01'
) }}
SELECT
session_id,
user_id,
MIN(viewed_at) AS session__started_at,
MAX(viewed_at) AS session__ended_at,
COUNT(*) AS session__page_views
FROM {{ ref('base__app__page_views') }}
GROUP BY session_id, user_id

Si base__app__page_views a event_time='viewed_at' configuré dans sa propre définition de modèle, dbt injecte un filtre temporel sur viewed_at pour chaque batch. Lors du traitement du batch du 10 janvier, dbt filtre base__app__page_views pour ne retourner que les lignes où viewed_at se trouve dans la fenêtre du 10 janvier.

Le SQL généré devient effectivement :

-- Ce que dbt génère en coulisses (par batch)
SELECT ...
FROM base__app__page_views
WHERE viewed_at >= '2024-01-10 00:00:00'
AND viewed_at < '2024-01-11 00:00:00'

Ce filtre n’est jamais écrit manuellement. dbt le gère en se basant sur la configuration event_time du modèle en amont et le batch_size du modèle consommateur.

Tables de dimension et lectures complètes

Tous les modèles en amont n’ont pas event_time. Les tables de dimension — produits, utilisateurs, tables de configuration — n’ont généralement pas d’horodatage significatif pour le filtrage temporel. Quand un modèle microbatch référence un modèle sans event_time, dbt lit la table complète pour chaque batch.

-- Ce modèle n'a pas event_time configuré
-- dbt lit toutes les lignes pour chaque batch
SELECT
product_id,
product_name,
product_category
FROM {{ ref('dim__products') }}

Pour les petites tables de dimension (des milliers à quelques millions de lignes), c’est acceptable. La lecture complète est rapide et les données sont nécessaires dans leur intégralité pour les lookups et jointures. Mais si l’on référence un grand modèle sans event_time — par exemple, une table de faits dénormalisée utilisée pour l’enrichissement — chaque batch déclenche un scan complet de cette table. Sur BigQuery avec la tarification à la demande, ces scans s’accumulent rapidement sur 30 batchs ou plus.

Si un grand modèle en amont n’a genuinement pas de dimension temporelle, il convient de se demander s’il doit être la source pour un modèle microbatch. Le profil de coût de microbatch suppose que la plupart des données en amont peuvent être filtrées temporellement.

Se désinscrire avec .render()

Parfois on veut forcer une lecture complète de table même quand le modèle en amont a event_time configuré. La méthode .render() sur un appel ref() désactive le filtrage automatique :

-- Forcer la lecture complète, en contournant le filtrage event_time automatique
SELECT
product_id,
product_name,
product_category
FROM {{ ref('mrt__product__products').render() }}

Quand est-ce nécessaire ? Le scénario le plus courant est quand un modèle microbatch a besoin de joindre un modèle qui a event_time mais où l’on a besoin du jeu de données complet, pas seulement la fenêtre du batch courant. Par exemple, une table de dimension à évolution lente qui a une colonne updated_at configurée comme event_time — on ne veut pas que dbt la filtre aux seules mises à jour d’aujourd’hui quand on a besoin de l’état actuel complet de chaque ligne.

Autre cas : les modèles d’enrichissement où event_time représente quand l’enrichissement a eu lieu, pas quand l’entité sous-jacente était pertinente. Filtrer à la fenêtre du batch courant exclurait des enregistrements enrichis plus tôt mais toujours valides pour les jointures.

Interaction avec lookback

Le filtrage automatique en amont respecte la configuration lookback. Avec lookback=3 et batch_size='day', lors du traitement du batch d’aujourd’hui, dbt retraite également les trois jours précédents. Le filtre en amont s’élargit en conséquence — base__app__page_views est filtré sur la fenêtre de quatre jours (aujourd’hui plus trois jours de lookback), pas seulement aujourd’hui.

Cela signifie que la fenêtre de lookback s’applique de façon cohérente à la fois à la sortie du modèle et à ses entrées. Les enregistrements en amont arrivant en retard dans la fenêtre de lookback sont automatiquement inclus dans le retraitement.

Implications de coût selon les entrepôts

L’impact sur le coût du filtrage automatique en amont varie selon l’entrepôt :

BigQuery : L’impact le plus significatif. La tarification à la demande de BigQuery est facturée par octets scannés. Le filtrage automatique qui tire parti du partition pruning sur une table en amont partitionnée par temps peut réduire les octets scannés de plusieurs ordres de grandeur. Si la table en amont est partitionnée par la même colonne utilisée comme event_time, chaque batch scanne uniquement les partitions pertinentes.

Snowflake : Le micro-partition pruning de Snowflake bénéficie des filtres temporels, mais le modèle de coût est basé sur les slots plutôt que sur le scan. L’amélioration des performances est réelle (moins de données traitées par batch), mais les économies de coût sont moins spectaculaires que sur BigQuery car on paie pour le temps de calcul, pas pour les octets scannés.

Databricks : Similaire à Snowflake. Le data skipping de Delta Lake et le Z-ordering peuvent amplifier le bénéfice des filtres temporels, surtout si la table en amont est optimisée pour la colonne event_time.

Concevoir pour le filtrage automatique

Pour tirer le meilleur de cette fonctionnalité, configurez event_time sur tous les modèles de séries temporelles du DAG, pas seulement les modèles microbatch eux-mêmes. Quand les modèles de la couche base, les agrégations intermédiaires et les modèles de staging déclarent tous leur colonne d’horodatage comme event_time, le filtrage automatique se propage à travers toute la chaîne de dépendances.

# Dans le YAML du modèle base
models:
- name: base__app__page_views
config:
event_time: viewed_at
- name: base__app__events
config:
event_time: event_occurred_at

C’est une configuration unique qui permet le filtrage automatique pour chaque modèle microbatch en aval. Sans event_time configuré sur les modèles en amont, chaque batch lit la table en amont complète quelle que soit la taille du batch.