ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Impact des matérialisations dbt sur les coûts BigQuery

Comment les choix de matérialisation dbt affectent les coûts BigQuery — compromis table vs vue vs ephemeral, l'anti-pattern des chaînes de vues, et pourquoi choisir les tables par défaut s'avère généralement gagnant.

Planté
dbtbigquerycost optimizationdata modeling

Sur BigQuery, où vous payez par octet scanné, le choix de matérialisation dbt détermine le profil de coût de base de chaque modèle. Le coût se cumule sur chaque requête downstream et chaque exécution dbt.

Les Trois Matérialisations et leurs Profils de Coût

Table : Scan complet lors de la construction, puis coûts de stockage. Chaque requête downstream lit depuis la table matérialisée — aucun recalcul, aucun scan upstream. Le coût de construction est une dépense unique par exécution. Les requêtes downstream sont aussi peu coûteuses que possible parce qu’elles ne scannent que le résultat matérialisé, pas les données sources originales.

Vue : Zéro coût de construction, zéro coût de stockage. Cela paraît gratuit — ce ne l’est pas. Chaque requête sur une vue déclenche une exécution complète du SQL sous-jacent, ce qui signifie scanner toutes les tables upstream. Pour des transformations complexes ou des vues interrogées fréquemment, le coût de calcul cumulé dépasse largement ce qu’aurait coûté la matérialisation en table.

Ephemeral : Aucun stockage, aucune construction. Le modèle est interpolé comme un CTE dans chaque modèle qui le référence. Voici le piège : BigQuery ne matérialise pas les CTE non récursifs. Chaque référence réexécute le scan sous-jacent. Un modèle ephemeral référencé par trois modèles downstream signifie trois scans séparés des données sources. Les modèles ephemeral sont aussi difficiles à déboguer puisqu’ils n’existent pas en tant qu’objets interrogeables dans BigQuery.

La comparaison de coûts pour une transformation source de 100 Go interrogée 10 fois par jour :

MatérialisationCoût de constructionCoût par requêteTotal quotidien
Table0,63 $~0,01-0,10 $ (lit un résultat plus petit)~1,63 $
Vue0 $0,63 $ (scan complet des sources à chaque fois)6,30 $
Ephemeral0 $0,63 $ (par modèle référençant)6,30 $+

Les vues coûtent 4 fois plus dans ce scénario. Pour des modèles interrogés 50 fois par jour (dashboards, multiples dépendances downstream), le multiplicateur atteint 20x ou plus.

L’Anti-Pattern des Chaînes de Vues

L’erreur la plus coûteuse dans dbt sur BigQuery est d’enchaîner des vues entre elles. Rien ne calcule jusqu’à ce qu’une requête atteigne une matérialisation en table, moment auquel toutes les vues upstream dans la chaîne s’exécutent.

Considérez une lignée comme celle-ci :

base__events (vue) → int__events__enriched (vue) → int__events__sessionized (vue) → mrt__daily_sessions (table)

Quand dbt construit mrt__daily_sessions, BigQuery exécute le SQL des trois vues upstream dans une seule requête en cascade. Le total des octets scannés est égal à la somme de ce que chaque vue scannerait indépendamment.

Mais le coût ne s’arrête pas au moment de la construction dbt. Si un analyste interroge int__events__enriched directement (pour l’exploration ou le débogage), BigQuery scanne base__events en coulisses. Si un autre modèle référence aussi int__events__sessionized, c’est une autre cascade complète. Chaque consommateur de n’importe quelle vue dans la chaîne déclenche le calcul complet upstream.

Le package dbt_project_evaluator de dbt signale les chaînes de 4 vues ou plus comme problématiques. L’avertissement existe parce que les chaînes de vues ne coûtent pas de façon linéaire — elles coûtent de façon multiplicative sur chaque consommateur downstream et chaque requête ad hoc.

Pourquoi les Tables Gagnent sur BigQuery

Étant donné que les coûts de stockage sont négligeables par rapport au calcul (85-90% calcul vs 10-15% stockage), le calcul sur BigQuery est clair : matérialiser en tables est presque toujours moins cher qu’utiliser des vues.

Une table de 10 Go stockée pendant un mois coûte 0,20 $. Scanner ces mêmes 10 Go une fois coûte 0,0625 $ à la demande. Si l’équivalent en vue serait interrogé même quelques fois, la table s’amortit largement sur le stockage.

La recommandation par défaut pour la plupart des projets dbt sur BigQuery :

dbt_project.yml
models:
my_project:
base:
+materialized: table
intermediate:
+materialized: table
marts:
+materialized: table
+partition_by:
field: created_date
data_type: date

Cette approche matérialise tout en tables sur les trois couches de l’architecture dbt. Les tables de la couche mart reçoivent un partitionnement par défaut, et vous ajoutez du clustering sur des modèles spécifiques selon les besoins.

Les vues peuvent fonctionner pour des transformations vraiment simples qui sont rarement interrogées — un modèle base qui renomme des colonnes et n’est référencé que par une seule table downstream, par exemple. Mais le risque de coût des vues croît avec la fréquence des requêtes et la complexité upstream. En cas de doute, utilisez une table.

Sélection de Colonnes dans les Modèles dbt

Au-delà du type de matérialisation, les colonnes que vous sélectionnez dans vos modèles dbt affectent directement le coût. Le stockage en colonnes de BigQuery signifie que chaque colonne est stockée et scannée séparément. Sélectionner toutes les colonnes quand vous n’en avez besoin que de quelques-unes est l’une des erreurs de coût les plus courantes dans les projets dbt.

Le pattern négligent :

-- Coûteux : scanne toutes les colonnes du modèle base
SELECT * FROM {{ ref('base__analytics__events') }}

Le pattern économe :

-- Mieux : colonnes explicites, uniquement ce dont le downstream a besoin
SELECT
event_id,
user_id,
event_timestamp,
event_type
FROM {{ ref('base__analytics__events') }}

Pour une table large à 50 colonnes dont vous n’avez besoin que de 5, la sélection explicite de colonnes réduit le coût de scan de 90%. Cela s’applique à chaque couche de votre projet dbt : les modèles base doivent sélectionner uniquement les colonnes que les modèles downstream utilisent réellement, les modèles intermédiaires ne doivent propager que ce dont les marts ont besoin, et les marts ne doivent exposer que ce que les consommateurs interrogeront.

Cette discipline est plus difficile à maintenir qu’il n’y paraît. Les colonnes s’accumulent pendant le développement (“ajoutons ça au cas où”), et personne ne les supprime. Des audits périodiques des colonnes que les modèles downstream référencent réellement permettent d’identifier les colonnes mortes qui gonflent silencieusement les coûts.

Incrémental : Le Niveau Suivant

Une fois que vous avez défini table comme matérialisation par défaut, le levier de coût suivant est les modèles incrémentaux. Une matérialisation en table scanne et réécrit la table entière à chaque exécution dbt. Pour une table de 500 Go qui tourne quotidiennement, cela représente 3,13 $ par exécution ou environ 94 $ mensuels rien que pour la reconstruction.

Les modèles incrémentaux ne traitent que les données nouvelles ou modifiées, et les économies s’accumulent avec la taille de la table et la fréquence des exécutions. La combinaison d’une matérialisation par défaut en table pour les modèles petits à moyens et d’une matérialisation incrémentale pour les grands modèles est la stratégie de coût optimale pour dbt sur BigQuery.

Le seuil de décision : envisagez de passer un modèle de table à incrémental quand :

  • La table source dépasse 100 Go
  • Le modèle s’exécute plus d’une fois par jour
  • La transformation est essentiellement en append (nouvelles lignes, pas de mises à jour de lignes existantes)

Pour les détails de configuration des modèles incrémentaux sur BigQuery — y compris le choix critique entre les stratégies merge et insert_overwrite — consultez Modèles incrémentaux dans dbt et le Cadre de décision des stratégies incrémentales.

Le Projet dbt Économe

Un projet dbt optimisé sur BigQuery suit ces principes :

  1. Matérialisation en table par défaut sur toutes les couches
  2. Sélection explicite des colonnes plutôt que SELECT * à chaque couche
  3. Ajout du partitionnement aux tables de la couche mart et à toute table de plus de 100 Go
  4. Ajout du clustering aux tables filtrées fréquemment de plus de 64 Mo
  5. Passage en incrémental pour les grandes tables essentiellement en append
  6. Utilisation de insert_overwrite avec des partitions statiques comme stratégie incrémentale
  7. Définition de maximum_bytes_billed dans profiles.yml comme filet de sécurité
  8. Ne jamais enchaîner des vues — si vous devez utiliser des vues, limitez-les à une seule couche avec des matérialisations en table des deux côtés

Ces configurations évitent les problèmes de coût cumulatifs qui peuvent multiplier une facture BigQuery de 500 $/mois par un ordre de grandeur.