dbt

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

2026-04-19
NicheeLab編集部

dbt のモデルは、SQL の SELECT 文で定義する変換の最小単位です。1ファイル=1モデル=1つのSELECTという単純なルールが、変更に強いDAGと再現性の高い開発体験をもたらします。

本稿では、モデルの基本設計からマテリアライゼーション選択、ref/source による依存関係管理、インクリメンタルの基礎、テストと運用まで、試験で問われやすい観点を実務ベースで整理します。

dbt Model の定義と役割

dbt におけるモデルは、models ディレクトリ配下の .sql ファイルで定義する SELECT 文です。Jinja を用いたテンプレート化が可能で、ref や source、マクロ、変数、config ブロックを組み合わせて環境に依存しない変換を表現します。

モデルは単一の SELECT を基本とし、DML を直接書かず、永続化の方法はマテリアライゼーションに委ねます。命名はレイヤ別の接頭辞(stg_, int_, dim_, fct_ など)とスネークケースが管理上有効です。資格試験では、モデルが DAG のノードになり、マテリアライゼーションによりオブジェクト化の有無が変わる点がよく問われます。

  • 1モデル=1 SELECT。CTEは可、INSERT/UPDATE/DELETE は書かない(永続化は materialized に委譲)。
  • Jinja の config で materialized, tags, alias, schema などを宣言可能。
  • コンパイル時にアダプタ(Snowflake, Databricks など)向けの SQL に展開される。

最小のモデル例(staging レイヤの view)

{{ config(materialized='view', tags=['staging']) }}

select
  id,
  user_id,
  event_type,
  event_ts
from {{ source('raw', 'events') }}
where event_ts >= dateadd(day, -30, current_timestamp)

マテリアライゼーション設計の基本

dbt のモデルは materialized パラメータで永続化の方法を選べます。代表は view, table, incremental, ephemeral。実体化の度合い・リフレッシュコスト・実行速度・下流からの参照可否が主なトレードオフです。

プロジェクト全体の既定値は dbt_project.yml で上書きし、例外的なモデルはファイル内の config で個別指定します。試験では、ephemeral は中間オブジェクトを作らずコンパイル時に上位モデルへ CTE 内挿される点、incremental は部分更新である点が頻出です。

  • デフォルトはアダプタやプロジェクト設定に依存。必要に応じてモデル単位で上書き。
  • 開発中は view、本番で安定化したら table/incremental へ昇格、が運用パターンとして無難。
種類特徴リフレッシュ戦略ストレージコスト
view常に最新を参照(仮想ビュー)再作成は軽量、実データは保有しない
table物理テーブルを作成全件再作成(完全リビルド)中〜高
incremental差分適用(部分更新)新規/更新分のみ投入(MERGE等)
ephemeralオブジェクト非作成(CTE内挿)該当なしゼロ

マテリアライゼーション指定(モデル内とプロジェクト設定)

-- モデルファイル内で個別指定
{{ config(materialized='incremental', unique_key='id') }}
select * from {{ ref('stg_orders') }}

# dbt_project.yml で既定値をレイヤ単位に設定
models:
  my_project:
    +materialized: table
    staging:
      +materialized: view
    marts:
      +materialized: table

ref と source による依存関係管理

ref は他モデルを論理名で参照し、コンパイル時に正しいスキーマ・オブジェクト名へ解決しつつ、依存関係をDAGに登録します。source は外部の生データオブジェクトを宣言的に取り込みます。これらにより、環境差異を吸収しつつ正しい順序でビルドされます。

dbt build はモデル作成・テスト・スナップショット・シードを依存順に包括実行します。選択子(--select/--exclude)と組み合わせて、影響範囲のみの安全なビルドが可能です。

  • source は yml で宣言し、source('source_name','table_name') で参照。
  • ref はモデル名の変更やスキーマの差異を吸収。手書きの完全修飾名は避ける。

モデルDAGのイメージ

source(raw.orders)stg_ordersint_orders_enricheddim_usersfct_ordersモデルDAGのイメージ

source の宣言と ref/source の併用例

# models/sources.yml
version: 2
sources:
  - name: raw
    database: RAW_DB
    schema: RAW_SCHEMA
    tables:
      - name: orders
      - name: users

-- models/stg_orders.sql
{{ config(materialized='view', tags=['staging']) }}
select *
from {{ source('raw', 'orders') }}

-- models/fct_orders.sql
{{ config(materialized='table', tags=['marts']) }}
select
  o.id,
  o.user_id,
  u.country,
  o.total_amount,
  o.order_ts
from {{ ref('int_orders_enriched') }} o
join {{ ref('dim_users') }} u on o.user_id = u.user_id

インクリメンタルモデルの基礎

incremental は大規模テーブルの再計算コストを抑えるための部分更新戦略です。unique_key やパーティション列で新規・更新レコードを特定し、is_incremental() を用いて初回と以降の処理を分岐させます。実際の差分適用方法(MERGE/INSERT OVERWRITE 等)はアダプタ実装に依存します。

スキーマが変わる可能性がある場合は on_schema_change の扱いを検討します。全件作り直したい場合は --full-refresh を付けて実行します。試験では、インクリメンタルが『部分更新』『初回フルビルド』『unique_key で更新検出』をキーワードとして問われます。

  • unique_key は更新検出の基礎。なければ新規挿入のみになることが多い。
  • is_incremental() で増分時だけのフィルタを実装し、取り込み範囲を絞る。

インクリメンタルモデルの典型パターン

{{ config(
  materialized='incremental',
  unique_key='id',
  on_schema_change='sync_all_columns'
) }}

with src as (
  select * from {{ ref('stg_orders') }}
  {% if is_incremental() %}
    where order_ts > (select coalesce(max(order_ts), '1900-01-01') from {{ this }})
  {% endif %}
),
calc as (
  select id, user_id, total_amount, order_ts, total_amount * 0.1 as tax
  from src
)
select * from calc

モデルのテストとドキュメント

モデルの品質はスキーマファイル(yml)で宣言的にテストします。not_null, unique, relationships などの汎用テストに加え、必要なら SQL を書く単体(singular)テストも利用します。dbt build はモデルとテストを依存順に実行します。

ドキュメントはカラム記述やソース説明を yml に記載し、dbt docs generate/serve でブラウズ可能です。説明文は将来のメンテナと試験の双方で重要な資産になります。

  • テストは失敗時にモデルの不整合を早期検知。CI での実行を推奨。
  • docs はDAGと系譜を可視化。カラム記述を欠かさない。

スキーマテスト例(generic と singular)

# models/marts/schema.yml
version: 2
models:
  - name: fct_orders
    description: 受注のファクトテーブル
    columns:
      - name: id
        tests: [not_null, unique]
      - name: user_id
        tests:
          - relationships:
              to: ref('dim_users')
              field: user_id

# tests/high_value_orders.sql(singular テスト)
select 1
where exists (
  select 1 from {{ ref('fct_orders') }} where total_amount < 0
)

実行・選択・パフォーマンスの要点

dbt run はモデルを、dbt build はモデル・テスト・スナップショット・シードを依存順に実行します。--select/--exclude で影響範囲を限定し、タグやパス、依存グラフ演算子(+ や @)を活用します。state:modified を用いると変更検出に基づく選択が可能です。

パフォーマンス面では、上流の集計やフィルタはなるべく早いレイヤ(staging では軽く、intermediate で正規化・集約、marts でビジネスロジック)に配分します。倉庫固有のパーティション/クラスタキー設定はモデルの DDL オプション(アダプタ依存の config)で管理します。

  • 影響範囲のみ実行: dbt build --select state:modified+
  • タグ駆動: dbt run --select tag:staging; パス指定: dbt run --select models/marts/
  • フルリフレッシュ: dbt run --full-refresh --select fct_orders

代表的な選択子の例

# 変更のあったモデルとその下流をビルド
dbt build --select state:modified+

# あるモデルの上流も含めて実行
dbt run --select +int_orders_enriched

# 2つのタグを持つモデルのみ
dbt run --select tag:marts,tag:critical

# 失敗したノードを再実行
dbt build --select result:error

問題で確認

Analytics Engineer

問題 1

下流の1つのモデルだけで使う小さな補助変換を作りたい。中間オブジェクトをウェアハウス上に作成せず、コストを最小化したい。この補助変換に最適なマテリアライゼーションはどれか。

  1. view
  2. table
  3. incremental
  4. ephemeral

正解: D

ephemeral は物理オブジェクトを作らず、親モデルにCTEとして内挿されます。中間テーブルの作成・クリーンアップが不要で、単一下流でのみ使う補助変換に最適です。

よくある質問

モデル名を変更したいが下流への影響を抑えるには?

ref を使っていれば論理名解決のためビルド順序は自動調整されます。リネーム時は git の差分と state:modified セレクタで影響範囲をビルドし、dbt test で関係テストが通ることを確認します。必要に応じて alias で旧物理名を維持しつつ移行も可能です。

インクリメンタルでカラムが増減した場合は?

on_schema_change 設定を用います。sync_all_columns などの動作はアダプタ依存です。重大な変更や型変更を伴う場合は --full-refresh を選び、マイグレーションの安全性を優先します。

ソースの遅延データ(遅延到着更新)に対応するには?

unique_key を定義した上で is_incremental() 内の取り込み条件を『最大タイムスタンプより少し前』まで拡張する、もしくは適切な MERGE 条件を設定します。必要に応じて定期的なフルリフレッシュやウィンドウ再計算のバッチを併用します。

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

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

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

NicheeLab編集部

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


関連記事
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

dbt profiles.yml と接続管理:環境別のベストプラクティス

dbt Core/Cloud で profiles.yml を用いて dev/stg/prod など環境別に接続を切り替...

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