dbtモデルの構築
使用すべき状況
- dbtプロジェクトで
.sqlモデルを作成またはリファクタリングする場合。 - マテリアライゼーション(view / table / incremental / ephemeral)を決定する場合。
- レイヤー(staging → intermediate → marts)を構造化する場合。
- 大規模で増大するテーブルに対してインクリメンタルモデルを記述する場合。
- テストの作成には使用しないでください(
testing-dbt-projectsを使用)。また、実行失敗のデバッグには使用しないでください(debugging-dbt-runsを使用)。
ワークフロー
- [ ] モデルを適切なレイヤー(staging/intermediate/marts)に配置する
- [ ] 上流の参照はref()/source()のみを使用 — ハードコードされた名前は使用しない
- [ ] サイズと更新要件に基づいてマテリアライゼーションを選択する
- [ ] インクリメンタルモデルの場合、unique_key + is_incremental()フィルタを設定する
- [ ] テストを含むschema.ymlエントリを追加する
- レイヤリング。
staging/= ソーステーブルごとに1モデル、軽いリネーム/型変換、ビューとしてマテリアライズ。intermediate/= 再利用可能なビジネスロジック。marts/= BIで利用される最終的なディメンショナルモデル、テーブルとしてマテリアライズ。 - 正しく参照する。
{{ ref('stg_orders') }}と{{ source('shop', 'orders') }}を使用して、dbtがDAGを構築し環境を管理できるようにします。生のスキーマ.テーブル名は決して記述しないでください。 - マテリアライゼーションを選択: view(低コスト、常に最新、小規模)、table(高速読み取り、実行ごとに再構築)、incremental(大規模な追加/更新テーブル)、ephemeral(インラインCTE、オブジェクトなし)。
- インクリメンタルモデル は新しい行または変更された行のみを処理します。
パターン
Stagingモデル — ソースごとに1つ、薄く一貫性を保つ:
-- 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
インクリメンタルモデル — 新しい行にフィルタリングし、冪等なマージキーを設定:
{{ config(materialized='incremental', unique_key='order_id',
incremental_strategy='merge') }}
select * from {{ ref('stg_orders') }}
{% if is_incremental() %}
-- すでにロード済みのものより新しい行のみ、遅延データを考慮してルックバック
where ordered_at >= (select coalesce(max(ordered_at), '1900-01-01') from {{ this }})
- interval '3 days'
{% endif %}
unique_key + merge により再実行が冪等になります。ルックバックは遅延到着行をキャッチします。BigQuery/Sparkでは、日付パーティションに対して insert_overwrite を推奨します。
よくある落とし穴
- ハードコードされたテーブル名 を
ref()/source()の代わりに使用 — DAG、系統、環境切り替えが壊れます。 unique_keyなしのインクリメンタル — 再実行で重複が追記されます。- ルックバックなしの
max(id)インクリメンタルフィルタ — 遅延データが静かに欠落します。 - stagingでのビジネスロジック — stagingは薄く保ちます。結合/集計はintermediate/martsに属します。
- すべてを
tableとしてマテリアライズ — ウェアハウス時間を浪費します。小規模/低コストモデルにはビューを、大規模モデルにはインクリメンタルを使用します。 - 一つの巨大なモデル — テスト容易性と再利用性のために中間ステップに分割します。