dbt : fondamentaux
Résumé
dbt (data build tool) transforme des données déjà chargées dans un entrepôt : c’est l’approche ELT (charger d’abord, transformer ensuite, dans l’entrepôt lui-même), à l’inverse de l’ETL qui transforme avant de charger. Chaque modèle est un
SELECTversionné. dbt s’occupe de créer la table ou la vue, de déterminer l’ordre d’exécution, d’exécuter les tests et de générer la documentation.
Prérequis
SQL, et la distinction entre une table, une vue et une table matérialisée. Glossaire : Glossaire data engineering (DAG, Jinja, ELT).
Un modèle minimal
Un modèle est un fichier .sql qui contient un SELECT. ref() désigne un autre modèle, source() une table brute.
-- models/staging/shop/stg_orders.sql
select
id as order_id,
customer_id,
cast(created_at as timestamp) as ordered_at,
amount_cents / 100.0 as amount
from {{ source('shop', 'orders') }}-- models/marts/fct_daily_revenue.sql
select
date(ordered_at) as order_date,
sum(amount) as revenue
from {{ ref('stg_orders') }}
group by 1Parce que le second modèle appelle ref('stg_orders'), dbt sait qu’il doit construire le premier avant. L’ensemble de ces dépendances forme un DAG (graphe orienté sans cycle).
La source brute et les tests se déclarent dans un fichier .yml à côté :
sources:
- name: shop
tables:
- name: orders
models:
- name: stg_orders
columns:
- name: order_id
data_tests:
- unique
- not_nullLa clé data_tests est valable à partir de dbt 1.8 ; les versions précédentes utilisent tests.
Lancer le projet
| Commande | Effet |
|---|---|
dbt run | Construit les modèles dans l’ordre du DAG |
dbt test | Exécute les tests |
dbt build | Construit les modèles, exécute les tests, les snapshots et les seeds, dans l’ordre du DAG |
dbt snapshot | Capture l’état des tables suivies par un snapshot |
Concepts clés
| Concept | Rôle |
|---|---|
source() | Désigne une table brute chargée hors dbt, déclarée dans un .yml |
ref() | Désigne un autre modèle et construit le DAG |
| Matérialisation | La forme physique du modèle : voir ci-dessous |
| Test | Assertion déclarative sur un modèle (not_null, unique, relationships, ou test SQL personnalisé). Sévérité error (échoue le run) ou warn |
| Snapshot | Capture l’état d’une table à chaque exécution de dbt snapshot, pour reconstituer un historique de type SCD 2 |
| Macro | Fonction écrite en Jinja (langage de gabarit) qui génère du SQL réutilisable |
Matérialisations
| Type | Ce que dbt construit | Coût principal |
|---|---|---|
view | Une vue, recalculée à chaque lecture | Calcul à chaque lecture |
table | Une table recréée à chaque run | Calcul à chaque run, lecture rapide |
incremental | Une table où seules les nouvelles lignes sont ajoutées ou fusionnées | Calcul réduit, logique de fenêtre à maîtriser |
ephemeral | Aucun objet : le modèle est inséré en CTE dans ses consommateurs | Aucun stockage |
materialized_view | Une vue matérialisée gérée par l’entrepôt (selon l’adapter) | Dépend du moteur |
Un modèle incrémental ne traite que les nouvelles lignes après le premier run :
{{ config(materialized='incremental', unique_key='order_id') }}
select order_id, customer_id, ordered_at, amount
from {{ ref('stg_orders') }}
{% if is_incremental() %}
where ordered_at > (select max(ordered_at) from {{ this }})
{% endif %}is_incremental() est faux au premier run (la table est créée en entier) et vrai ensuite ; {{ this }} désigne la table déjà construite. Ce filtre ignore les lignes en retard : c’est la limite que la note dbt Incremental Models vs Snowflake Dynamic Tables détaille.
La stratégie microbatch des modèles incrémentaux (traitement par tranches de temps) existe dans les versions récentes de dbt ; la disponibilité dépend de la version et de l’adapter. Voir dbt Incremental Models vs Snowflake Dynamic Tables.
Les contraintes ne sont pas toujours appliquées
Sur BigQuery, déclarer une clé primaire ou étrangère n’impose rien : ces contraintes sont informatives. Seul un test dbt vérifie réellement l’unicité.
Organisation en couches
La convention dbt recommande trois couches. Elle ressemble au flux décrit dans Staging, ODS, DWH et architecture médaillon sans lui être identique.
| Couche | Rôle | Matérialisation courante |
|---|---|---|
staging (stg_) | Un modèle par source brute : renommage, cast de types, aucune jointure | view |
intermediate (int_) | Jointures et logique métier partagées entre plusieurs marts | view ou ephemeral |
marts (fct_, dim_) | Modèles finaux pour la BI, faits et dimensions | table ou incremental |
Le coût d'une vue
Une vue n’occupe pas de stockage, mais son calcul est refait à chaque lecture. Sur BigQuery, interroger une vue de staging relit et refacture les tables sous-jacentes. En staging, c’est acceptable quand le volume est petit ou que la vue n’est lue que par les modèles suivants lors d’un run. Si une vue de staging est lue souvent par des outils externes, une table devient plus économique.
Exemple d’arborescence
Un projet organisé en couches :
models/
├── staging/ view
│ ├── shop/
│ ├── payments/
│ └── reference/
├── intermediate/ view
└── marts/ table
├── finance/
└── product/Choix courants :
- Staging et intermediate en
viewquand les volumes sont modestes : le recalcul à la lecture reste peu coûteux. - Marts en
table: les modèles finaux sont recalculés à chaque run pour des lectures rapides côté BI. - Monitoring dans le même projet : voir dbt_bigquery_monitoring pour surveiller le coût du projet.
Notes liées
- dbt Incremental Models vs Snowflake Dynamic Tables : approfondir
incremental. - dbt_bigquery_monitoring : surveiller le coût d’un projet dbt.
- Staging, ODS, DWH et architecture médaillon : l’architecture que la convention de couches implémente.
- dbt et le lakehouse : dbt sur des formats de table ouverts.
- Glossaire data engineering : DAG, Jinja, ELT.
- MOC Data Engineering : carte du vault.