Ce paragraphe décrit une stratégie avancée d’ingénierie de données dans dbt, utilisée lorsqu’on travaille avec des matérialisations complexes (souvent en materialized_view
ou table
) contenant des agrégations lourdes, et qu’on souhaite à la fois :
- 📈 garantir de bonnes performances pour les utilisateurs finaux
- 🔁 maintenir des données fraîches
- ✅ assurer la sécurité du rafraîchissement (pas d’interruption, possibilité de rollback)
🎯 Problème traité
Tu as une vue matérialisée ou une table agrégée contenant des données historiques ou volumineuses, par exemple :
SELECT
user_id,
DATE(created_at) AS jour,
COUNT(*) AS nb_commandes
FROM raw.commandes
GROUP BY user_id, DATE(created_at)
Et tu veux la rafraîchir quotidiennement avec les nouvelles données, sans recalculer toute l’historique, sans bloquer les utilisateurs, et sans corrompre les résultats si l’update échoue.
✅ Solution : incremental refresh pattern avec table de staging
Tu crées un modèle intermédiaire (staging) qui calcule les agrégations uniquement sur les nouvelles données,
puis tu les fusionnes proprement avec la table principale ou lamaterialized view
.
🧱 Architecture du pattern
[raw données] → [staging_agg] → [table ou materialized_view finale]
Étapes :
- ✅ Un modèle
stg_agg_commandes
calcule les nouvelles agrégations (par exemple, les données des 3 derniers jours) - ✅ Un modèle
agg_commandes
(matérialisé entable
oumaterialized_view
) fusionne le staging avec les données existantes - ✅ Optionnel : tu peux supprimer les jours existants et les remplacer par les jours recalculés (technique de “merge by partition”)
🛠 Exemple dans dbt
1. stg_agg_commandes.sql
— staging (temporaire, petits volumes)
{{ config(materialized='table') }}
SELECT
user_id,
DATE(created_at) AS jour,
COUNT(*) AS nb_commandes
FROM raw.commandes
WHERE created_at >= CURRENT_DATE - INTERVAL '3 day'
GROUP BY user_id, DATE(created_at)
2. agg_commandes.sql
— modèle final avec fusion logique
{{ config(
materialized='incremental',
unique_key='user_id || jour'
) }}
WITH base AS (
SELECT * FROM {{ this }}
{% if is_incremental() %}
WHERE jour < CURRENT_DATE - INTERVAL '3 day'
{% endif %}
),
updates AS (
SELECT * FROM {{ ref('stg_agg_commandes') }}
)
SELECT * FROM base
UNION ALL
SELECT * FROM updates
✅ Résultat :
- Tu gardes les anciennes données
- Tu ajoutes ou remplaces les lignes récentes
- Le tout se fait de façon atomique, sans bloquer les utilisateurs
🔐 Avantages du pattern
Avantage | Détail |
---|---|
✅ Performant | Tu ne recalcules que les nouvelles données |
✅ Sécurisé | Tu travailles d’abord dans une table de staging isolée |
✅ Pas de downtime | La table finale reste disponible pendant le traitement |
✅ Rollback facile | En cas d’erreur, la table finale n’est pas corrompue |
✅ Flexible | Compatible avec table ou materialized_view selon ton warehouse |
🧠 Quand utiliser ce pattern ?
Cas | Recommandé ? |
---|---|
Table avec millions de lignes et agrégations | ✅ Oui |
Tu dois rafraîchir régulièrement un sous-ensemble (ex : derniers jours) | ✅ Oui |
Tu ne peux pas faire de full refresh à chaque run | ✅ Oui |
Tu veux éviter de bloquer les requêtes BI | ✅ Oui |
Souhaites-tu que je t’écrive ce modèle complet dbt (avec tests + YAML) prêt à coller dans un projet ?