変更のないモデルまで毎回フルビルドしていると、CI が遅くコストも高くなります。dbt の state と defer は、直近の実行状態を参照して差分のみを実行し、未選択の依存は既存の本番テーブルへ安全に参照させることで、CI を安定かつ高速にします。
本稿は公式ドキュメントの動作に基づき、試験に出やすい選択子の挙動や、CI 設計の落とし穴も含めて解説します。環境やバージョンに依存しやすい箇所は慎重に言及します。
dbt の state は、過去の実行で生成されたアーティファクト(通常は manifest.json など)を参照し、現在のリポジトリ状態と比較して変更を検出します。defer は、ビルド対象に含めない依存関係について、本番環境など既に存在するリレーションを参照先として解決します。
これにより CI では、変更されたモデルとその影響範囲だけを実行しつつ、上流を安全に本番へ委譲でき、待ち時間とリソース消費を大幅に削減できます。
CI における state + defer の流れ
最小構成のコマンド例
dbt build \
--state ./artifacts/prod \
--defer \
--select state:modified+state は前回実行のアーティファクトと比較して、どのノードが新規・変更かを判定します。代表的には、モデルの SQL、本体に作用する設定値、テスト定義の変更などが比較対象になります。マクロの変更は広範囲に影響し得るため、関連ノードが変更扱いになる可能性に注意します。
差分の選択はセレクタで制御します。特に、末尾のプラスは子方向(下流)を、先頭のプラスは親方向(上流)を含めるという直感的だが試験で問われやすいポイントを押さえておきましょう。
| セレクタ | 含まれる範囲 | 主な用途 | 補足 |
|---|---|---|---|
| state:modified | 変更されたノードのみ | ピンポイントに変更分を実行 | テストは build で暗黙的に付随 |
| state:new | 新規ノードのみ | 新しく追加したモデルの検証 | 既存ノードは除外 |
| state:modified+ | 変更ノードとその子孫(下流) | 下流影響も含めて検証 | スキーマ互換性の確認に有効 |
| +state:modified | 変更ノードとその祖先(上流) | ソース〜変更点までの依存を再実行 | 上流更新が必要な時に使用 |
変更検出だけを一覧(実行はしない)
dbt ls --state ./artifacts/prod --select state:modifieddefer は、選択しなかった依存ノードの ref や source の参照先を、--state で与えたアーティファクトに記録された既存リレーションへ解決します。典型的には、本番環境で最後に成功した実行のアーティファクト一式を参照します。
これにより CI の一時スキーマでは上流を再構築せず、変更点のみを安全にビルドできます。ただし defer 先に該当リレーションが存在しない場合は参照エラーになるため、対象が本番で確実に存在することが前提です。
CI ターゲットで defer を使って変更分だけビルド
dbt build \
--target ci \
--state ./artifacts/prod \
--defer \
--select state:modified+実務では、本番実行で生成された target/ 配下(少なくとも manifest.json)が常に CI から参照できるように保管します。ワークフローとしては、本番ジョブの成功時にアーティファクトをストレージへ保存し、CI ではそれを取得して --state に渡します。
dbt Cloud では UI の設定で Production へ Defer でき、Cloud が内部的にアーティファクトを解決します。dbt Core の場合は手動でアーティファクトを用意します。
GitHub Actions の一例(概念)
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Restore prod artifacts
run: |
mkdir -p artifacts/prod
aws s3 cp s3://my-bucket/dbt/prod/last_success/ ./artifacts/prod --recursive
- name: Install dbt
run: pip install dbt-core dbt-bigquery # 例: ターゲットに合わせる
- name: Build changed nodes with deferral
run: |
dbt build \
--profiles-dir . \
--target ci \
--state ./artifacts/prod \
--defer \
--select state:modified+スキーマ非互換の変更(列削除やデータ型変更)を defer で見逃すと、子モデルの実行時に失敗します。変更ノードの子孫まで実行する state:modified+ をデフォルトとし、破壊的変更が疑われる場合は +state:modified+ などで広めに網をかけます。
増分モデルでは、未選択の上流を本番へ defer しても、実データの新旧差分が意図どおりになるとは限りません。クリティカルな経路はフルリフレッシュや限定的な再計算の検討が必要です。
変更分のモデルとテストをまとめて検証
dbt build \
--state ./artifacts/prod \
--defer \
--select state:modified+試験では、state セレクタの意味、+ の向き、defer の目的と前提(既存リレーションの参照)を問うパターンが多いです。CI 文脈のシナリオ問題にも備え、適切なコマンド例をそのまま書けるようにしておきましょう。
書き慣れておくコマンド
dbt ls --state ./artifacts/prod --select state:modified
dbt build --state ./artifacts/prod --defer --select state:modified+
dbt build --state ./artifacts/prod --defer --select +state:modified+Analytics Engineer
問題 1
本番に既存の上流テーブルがあり、CI では変更モデルとその下流のみを実行し、未選択の参照は本番を用いたい。最も適切なコマンドはどれか。
正解: A
要件は差分検出と本番への参照切替。--state と --defer を併用し、変更ノードと下流を含む state:modified+ を選ぶ A が適切。B は defer がない。C は上流を含めてしまい方針と異なる。D は新規ノードのみで要件に合わない。
state 用のアーティファクトは何を用意すればよいですか?
最低限 manifest.json を含む前回実行の target/ ディレクトリを用意します。実務では本番ジョブ成功時に target/ をアーカイブし、CI の --state にそのディレクトリを指定します。
defer は dbt Cloud と dbt Core で違いがありますか?
仕組みは同じですが、Cloud は環境設定で Production へ Defer 可能で、アーティファクトの取得を内製で扱います。Core は --defer と --state を自分で指定し、アーティファクトの保管・配布をパイプラインで実装します。
マクロを変更した場合、state:modified にどこまで反映されますか?
マクロの変更はそれを介してコンパイルに影響するノードで変更検出される可能性があります。影響範囲が広がる場合があるため、変更直後は dbt ls --state ... で選択結果を確認し、必要に応じて選択範囲を広げて実行してください。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
dbt Model の基礎: SQL で定義する変換の最小単位
Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...
dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点
dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...
dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点
dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...
dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト
Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....
dbt_project.yml の読み方:主要設定と命名を最短で掴む
dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...