dbt

dbt compile の役割を正しく掴む:Jinja/マクロの評価とSQL展開の実態

2026-04-19
NicheeLab編集部

dbt compile は「実行しない dbt」。Jinja とマクロを評価し、依存関係を解決して、実行可能なSQLに展開するが、テーブル・ビューを作らない。この境界を正しく理解すると、レビュー効率と失敗率が大きく変わる。

本稿では、公式ドキュメントの挙動に沿って compile の内部で何が起きているかを分解し、Analytics Engineer 試験で狙われやすいポイントと、現場で役立つ検証ワークフローを整理する。

dbt compile とは何か:目的と位置づけ

dbt compile は、プロジェクト内のモデル・スナップショット・テストなどのノードを読み込み、Jinja/マクロを評価し、ref/source/config などの依存を解決した上で、最終的に実行可能なSQLを target/compiled 配下へ出力するコマンドである。データベースには一切DML/DDLを発行しないため、安全に「最終SQL」を確認できる。

run や build の前段確認、レビュー用の差分検証、CIでの構文崩れ検知などに適する。特に ephemeral モデルのインライン化や adapter 固有マクロの展開結果を目視確認できる点は大きい。

  • Jinja/マクロを評価し、SQLテンプレートを「展開」する
  • ref()/source() を実テーブル・ビュー名へ解決する(FQNとスキーマ/エイリアスに基づく)
  • ephemeral モデルを参照側のCTEへインライン化する
  • データベースへは実行しない(DDL/DMLなし)
  • 出力は主に target/compiled と manifest.json

dbt の処理段階と compile の位置づけ

Parse (構文)ノード検出・依存関係グラフ生成Compile (展開/解決)Jinja/マクロ評価、ref/source解決Run (実行)DDL/DML実行、テーブル/ビュー作成manifest種 (中間)target/compiledtarget/run, run_resultsdbt の処理段階と compile の位置づけ

最小モデルの before/after(概念)

-- models/orders.sql(テンプレート)
with src as (
  select * from {{ source('raw', 'orders') }}
)
select * from src where order_date >= '{{ var('from_date', '2024-01-01') }}'

-- target/compiled/<project>/models/orders.sql(展開後の一例)
with src as (
  select * from RAW.SOURCE_ORDERS  -- adapterや命名規則でFQNに解決
)
select * from src where order_date >= '2024-01-01'

コンパイルで起きること:Jinja、マクロ、依存解決の順序

compile は、選択対象ノードを特定し、各リソースのSQLファイルをJinja環境でレンダリングする。マクロ呼び出しや adapter.dispatch によるアダプタ固有実装が展開され、ref/source は実際に作成(または作成予定)のリレーション名に置換される。ephemeral は上流に物理化されないため、参照側のクエリにCTEとして埋め込まれる。

tests は compile 段階で「失敗行を返すSELECT」などの実行用SQLに変換される。ただし compile 自体はそれを実行しない点が重要。

  • 選択: セレクタ/タグ/パス/プラス演算子に基づくノード集合の決定
  • レンダリング: Jinja評価、config()適用、マクロ展開
  • 解決: ref()/source()/exposure/metrics などの参照名をFQNへ置換
  • インライン化: materialized='ephemeral' はCTE化
  • 生成: 展開済みSQLを target/compiled へ書き出し、manifest.json を更新
コマンド主な目的生成物(ターゲット)実行(DDL/DML)
dbt parse構文解析とDAG生成manifest.json 等なし
dbt compileJinja/マクロ評価とSQL展開target/compiled, manifest.jsonなし
dbt runモデルSQLの実行target/run, run_results.jsonあり
dbt buildrun+test(+snapshot)の一括実行target/run ほかあり
dbt testテストSQLの実行target/run, run_results.jsonあり

ephemeral のインライン化イメージ

-- models/_dim_ephemeral.sql
-- {{ config(materialized='ephemeral') }}
select id, lower(email) as email_norm from {{ ref('stg_users') }}

-- models/dim_users.sql
select u.*, e.email_norm
from {{ ref('stg_users') }} u
left join {{ ref('_dim_ephemeral') }} e on u.id = e.id

-- target/compiled/.../dim_users.sql(概念)
select u.*, e.email_norm
from PROD.ANALYTICS.STG_USERS u
left join (
  select id, lower(email) as email_norm from PROD.ANALYTICS.STG_USERS
) e on u.id = e.id

出力アーティファクト:どこを見れば何がわかるか

compile 実行後、展開済みSQLは target/compiled/<project>/... に書き出される。これが「実行されるはずのSQL」の静的スナップショットとなる。manifest.json はDAGとメタデータ(リレーション名、依存、コンフィグ)を持ち、ツール連携や差分解析に有用である。

run や test と異なり、target/run は通常 compile では生成されない。実行ログや run_results.json を期待してはいけない。

  • target/compiled: 展開済みSQLの格納先(レビュー・静的検査に使用)
  • target/manifest.json: ノードメタデータとDAG(選択やCIの根拠として活用)
  • logs/dbt.log: レンダリング時の警告や未解決参照の手掛かり

典型的な出力のツリー

$ dbt compile --select +models/orders.sql

target/
  compiled/
    my_project/
      models/
        staging/
          stg_users.sql
        marts/
          orders.sql        # 展開後の最終SQL
  manifest.json            # DAGとメタデータ
logs/
  dbt.log

分岐と評価の注意点:is_incremental、変数、環境変数

compile は Jinja/マクロを実際に評価するため、変数 var()、環境変数 env_var()、config() による分岐、adapter.dispatch による方言分岐が反映される。一方で、SQL自体は実行されないため、実データに依存する条件分岐の最終的な効果までは検証できない。

is_incremental() はインクリメンタルモデル内の分岐に用いられるが、コンパイル時点のコンテキストや接続可否、既存リレーションの存在判定に依存する。compile はDDL/DMLを打たないが、マクロ評価のためにアダプタ情報を参照することがある。最終動作保証には run/build での確認が必要。

  • var('name', default) は --vars または dbt_project.yml の値で展開
  • env_var('NAME', default) はシェル環境から取り込まれる
  • adapter.dispatch により、Snowflake/BigQuery/Redshiftなどの方言差がSQLに反映
  • is_incremental() を使う分岐は compile 時点の前提に依存するため、最終確認は run/build で行う

インクリメンタル分岐の一例(compile時に展開)

-- models/fct_events.sql
{{ config(materialized='incremental', unique_key='id') }}
select * from {{ ref('stg_events') }}
{% if is_incremental() %}
  where _ingest_ts > (select max(_ingest_ts) from {{ this }})
{% endif %}

-- 注意: compile は上記を展開するが、既存テーブル有無などの前提は実行しない限り確定しない

選択とスコープ:compile でのセレクタと依存の扱い

compile の選択挙動は run と同様で、--select と --exclude、+(親子)演算子、タグ、リソース種別(model:、test: など)が使える。これにより、レビュー対象を最小限に絞り、差分箇所のみの展開を確認できる。

ephemeral 上流は参照先モデルにインライン化されるため、見落としを避けるには +演算子やパスベース選択で周辺ノードもコンパイルしておくのが安全。

  • --select marts.orders+ で依存する下流も含めて展開を確認
  • --select tag:critical で重要モデルだけを確認
  • --state を使った変更ノードのみの選択(CI最適化)
  • resource_type フィルタ(model:, test:, snapshot:)で対象を明確化

選択例

$ dbt compile --select path:models/marts/
$ dbt compile --select model:orders+
$ dbt compile --select state:modified --state ./target

トラブルシューティングと試験対策の要点

未定義の変数、未解決の ref/source、マクロのディスパッチ不一致は compile で発覚しやすい。まず dbt parse で構文段階のエラーを早期に潰し、その後 compile で展開結果を確認するワークフローが堅実だ。

Analytics Engineer 試験では、compile が「実行しない」「ephemeral をインライン化する」「ref/source をFQNへ解決する」「target/compiled と manifest.json を生成する」といった特性を選択肢で見極める問題が頻出する。実務では PR で compiled SQL を添付し、レビュー効率を高めるのが定石。

  • エラー例: 'Compilation Error: Required var not provided' → --vars か dbt_project.yml を確認
  • エラー例: 'ref not found' → 名前・package・選択スコープを確認
  • 方言差の検証: adapter.dispatch の展開結果を compiled で比較
  • CI: dbt parse → dbt compile → 条件分岐の静的チェック → dbt build(必要時)

デバッグの基本

$ dbt clean && dbt deps
$ dbt parse                # 構文とDAG
$ dbt compile -s +model:orders --vars '{from_date: 2024-01-01}'
$ tail -n 100 logs/dbt.log # マクロや未解決参照の痕跡を確認

問題で確認

Analytics Engineer

問題 1

dbt compile について正しい説明はどれか。最も適切なものを選べ。

  1. Jinja/マクロを評価し、ref()/source() を解決したSQLを target/compiled に出力するが、データベースに対しては実行しない。
  2. DAGの生成のみを行い、compiled SQL は出力しない。compiled は dbt run でのみ生成される。
  3. テストSQLを実行して run_results.json を出力するが、モデルは実行しない。
  4. ephemeral モデルを一時テーブルとして作成する。インライン化は dbt run のみで行われる。

正解: A

dbt compile はJinja/マクロ評価と依存解決を行い、展開済みSQLを target/compiled に書き出すが、DDL/DMLの実行はしない。Bは parse の説明に近く誤り、Cは test の挙動、Dは ephemeral の理解が誤りで、ephemeral はコンパイル時に参照側へインライン化される。

よくある質問

compile はデータベース接続を必要とするか?

ユーザーSQLの実行は行わないが、マクロ評価やアダプタ情報の参照で接続が初期化される場合がある。接続不要と仮定せず、適切なプロファイル設定を用意しておくのが安全。

target/compiled と target/run の違いは?

target/compiled は展開済みSQL(実行前の静的成果物)。target/run は run/test/build 実行時に使用されたSQLや一部生成物を格納する。compile では通常、target/run は作成されない。

compile の結果だけでインクリメンタル分岐は検証できる?

分岐の展開は確認できるが、既存テーブルの有無や最大タイムスタンプなど実データに依存する条件の最終挙動は compile だけでは保証できない。最終確認は run/build で行う。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
dbt

dbt Model の基礎: SQL で定義する変換の最小単位

Analytics Engineer 向けに、dbt Model の定義、マテリアライゼーション、依存関係、インクリメン...

dbt

dbt Analytics Engineer 試験ガイド: 出題範囲・配点・申込の実務視点

dbt Analytics Engineer 認定の出題範囲、配点の考え方、申込から受験までの流れを、公式ドキュメントの...

dbt

dbt Cloud と dbt Core の違いと選び方:Analytics Engineer 試験に効く要点

dbt Cloud と dbt Core の機能差を、実務と資格対策の両面から整理。スケジューリング、IDE、RBAC、...

dbt

dbt プロジェクト構造ガイド: models / seeds / macros の実務レイアウト

Analytics Engineer 向けに、dbt プロジェクトのディレクトリ構造と命名規約、dbt_project....

dbt

dbt_project.yml の読み方:主要設定と命名を最短で掴む

dbt_project.yml の必須キー、命名解決(database.schema.identifier)、設定優先度...

dbtの記事一覧 (101件)
© 2026 NicheeLab All rights reserved.