dbt-Modelle erstellen
Wann verwenden
- Erstellen oder Refaktorieren von
.sql-Modellen in einem dbt-Projekt. - Entscheidung über die Materialisierung (View / Tabelle / inkrementell / ephemeral).
- Strukturierung der Ebenen (Staging → Intermediate → Marts).
- Schreiben von inkrementellen Modellen für große, wachsende Tabellen.
- NICHT verwenden für das Verfassen von Tests (verwende
testing-dbt-projects) oder die Fehlerbehebung von Ausführungen (verwendedebugging-dbt-runs).
Arbeitsablauf
- [ ] Platziere das Modell in der richtigen Ebene (Staging/Intermediate/Marts)
- [ ] Referenziere vorgelagerte Modelle nur über ref()/source() – niemals hartcodierte Namen
- [ ] Wähle die Materialisierung basierend auf Größe und Aktualisierungsbedarf
- [ ] Setze bei inkrementellen Modellen unique_key + is_incremental()-Filter
- [ ] Füge einen Schema.yml-Eintrag mit Tests hinzu
- Ebene festlegen.
staging/= ein Modell pro Quelltabelle, leichte Umbenennung/Typkonvertierung, materialisiert als Views.intermediate/= wiederverwendbare Geschäftslogik.marts/= finale dimensionale Modelle, die von BI konsumiert werden, materialisiert als Tabellen. - Richtig referenzieren. Verwende
{{ ref('stg_orders') }}und{{ source('shop', 'orders') }}, damit dbt den DAG erstellt und Umgebungen verwaltet. Schreibe niemals rohe schema.table. - Materialisierung wählen: View (günstig, immer aktuell, klein), Tabelle (schnelles Lesen, wird bei jedem Lauf neu erstellt), inkrementell (große Append-/Update-Tabellen), ephemeral (inline als CTE, kein Objekt).
- Inkrementelle Modelle verarbeiten nur neue/geänderte Zeilen.
Muster
Staging-Modell – eines pro Quelle, dünn und konsistent:
-- models/staging/shop/stg_orders.sql
with source as (select * from {{ source('shop', 'orders') }})
select
order_id,
customer_id,
cast(order_ts as timestamp) as ordered_at,
round(amount_cents / 100.0, 2) as amount
from source
Inkrementelles Modell – filtere auf neue Zeilen und setze einen idempotenten Merge-Key:
{{ config(materialized='incremental', unique_key='order_id',
incremental_strategy='merge') }}
select * from {{ ref('stg_orders') }}
{% if is_incremental() %}
-- nur Zeilen, die neuer sind als bereits geladene, mit einem Lookback für verspätete Daten
where ordered_at >= (select coalesce(max(ordered_at), '1900-01-01') from {{ this }})
- interval '3 days'
{% endif %}
unique_key + merge macht Wiederholungsläufe idempotent; der Lookback fängt verspätet eintreffende Zeilen. Auf BigQuery/Spark bevorzuge insert_overwrite mit einer Datumspartition.
Häufige Fallstricke
- Hartcodierte Tabellennamen anstelle von
ref()/source()– zerstört den DAG, die Linage und den Umgebungswechsel. - Inkrementell ohne
unique_key– Wiederholungsläufe hängen Duplikate an. max(id)-inkrementeller Filter ohne Lookback – verwirft stillschweigend verspätete Daten.- Geschäftslogik im Staging – halte Staging dünn; Joins/Aggregationen gehören in Intermediate/Marts.
- Alles als
tablematerialisiert – verschwendet Warehouse-Zeit; verwende Views für kleine/günstige Modelle und inkrementelle für große. - Ein riesiges Modell – teile es in Intermediate-Schritte auf, um Testbarkeit und Wiederverwendbarkeit zu verbessern.