# dbt 2026年版ガイド:データ変換、テスト戦略、面接対策の完全解説 > dbtを使ったデータ変換の基礎から実践まで、レイヤードモデリング、インクリメンタル戦略、テスト手法、そして2026年のデータエンジニアリング面接で頻出する質問をコード例とともに解説する。 - Published: 2026-05-25 - Updated: 2026-05-25 - Author: SharpSkill - Tags: dbt, data-engineering, sql, data-transformation, interview - Reading time: 10 min --- dbt(data build tool)は、モダンデータウェアハウス内でのデータ変換における標準フレームワークとして定着しており、2026年現在、本番環境で40,000社以上が採用している。本チュートリアルでは、dbtによるデータ変換の仕組み、テスト戦略、そしてデータエンジニアリング面接で実際に問われる質問について、コード例を交えて解説する。 > **dbtの役割とは** > > dbtはELTにおける「T」(Transform)を担当するツールである。SQLのSELECT文をDDL(CREATE TABLE、CREATE VIEW、MERGE)にコンパイルし、Snowflake、BigQuery、Redshift、Databricksなどのウェアハウス上で実行する。バージョン管理、依存関係の解決、テスト、ドキュメント生成が標準で組み込まれている。 ## レイヤードモデリング:Staging、Intermediate、Marts 構造化されたdbtプロジェクトでは、変換処理を3つのレイヤーに分離する。この手法は[dbtコミュニティ](https://docs.getdbt.com/best-practices/how-we-structure/1-guide-overview)で広く支持されており、各モデルの責務を単一に保ち、デバッグを容易にする。 **Staging**モデルは生データに最も近いレイヤーに位置する。カラム名の変更、型のキャスト、不要な行のフィルタリングが主な役割であり、結合や集約は行わない。 ```sql -- models/staging/stg_orders.sql WITH source AS ( SELECT * FROM {{ source('ecommerce', 'raw_orders') }} ) SELECT id AS order_id, customer_id, CAST(order_date AS DATE) AS order_date, CAST(amount AS DECIMAL(10, 2)) AS order_amount, LOWER(status) AS order_status FROM source WHERE id IS NOT NULL ``` **Intermediate**モデルはビジネスロジックを適用する場所である。結合、集約、ウィンドウ関数などを使い、`ref()`を通じてStagingモデルを参照することでDAGに依存関係を登録する。 ```sql -- models/intermediate/int_customer_orders.sql WITH orders AS ( SELECT * FROM {{ ref('stg_orders') }} ), customers AS ( SELECT * FROM {{ ref('stg_customers') }} ) SELECT c.customer_id, c.customer_name, COUNT(o.order_id) AS total_orders, SUM(o.order_amount) AS lifetime_value, MIN(o.order_date) AS first_order_date, MAX(o.order_date) AS last_order_date FROM customers c LEFT JOIN orders o ON c.customer_id = o.customer_id GROUP BY c.customer_id, c.customer_name ``` **Marts**は最終的な消費レイヤーであり、ダッシュボードやアナリストが直接クエリする、整理されたドキュメント付きのテーブルを提供する。 このレイヤー構造により、ソースに障害が発生してもStagingレイヤーにのみ影響し、パイプライン全体に波及しない。各レイヤーは独立してテスト可能である。 ## ref()関数とDAGの依存解決 `ref()`は単なるエイリアスではない。`{{ ref('stg_orders') }}`を呼び出すと、コンパイル時に完全修飾テーブル名が解決されると同時に、dbtのDAG(有向非巡回グラフ)に依存関係のエッジが登録される。`ref()`を使わなければ、dbtは実行順序を決定できない。 よくある誤りは、`ref()`を使わずにテーブル名を直接記述することである。これは依存関係の追跡を破壊し、上流の依存先が準備完了する前にモデルが実行される可能性がある。 ```sql -- 悪い例:ハードコーディングされた参照、依存追跡なし SELECT * FROM analytics.stg_orders -- 良い例:ref()で依存関係を登録 SELECT * FROM {{ ref('stg_orders') }} ``` DAGは`dbt run --select stg_orders+`のような機能も支える。これはモデルとその下流すべてを実行するコマンドで、ソーススキーマの変更後にピンポイントで再ビルドする際に有用である。 ## マテリアライゼーション:適切なストレージ戦略の選択 dbtには4つのビルトイン[マテリアライゼーション](https://docs.getdbt.com/docs/build/materializations)が用意されており、アクセスパターンやデータ量に応じて使い分ける。 | マテリアライゼーション | ストレージ | 用途 | トレードオフ | |----------------|---------|----------|----------| | `view` | ストレージなし(読み取り時に計算) | 軽量な変換、小規模データ | 大量データでの読み取りが遅い | | `table` | 毎回テーブルを完全再構築 | Martレイヤー、高速読み取り | 全データを再構築、コスト高 | | `incremental` | 新規行のみ追加/マージ | 大規模ファクトテーブル、イベントストリーム | ロジックが複雑、`unique_key`が必要 | | `ephemeral` | CTEとしてインライン化、実体化しない | モデル間で共有する再利用ロジック | 直接クエリ不可 | デフォルトは`view`である。モデルのconfigブロックまたは`dbt_project.yml`で上書きできる。 ```sql -- models/marts/fct_daily_revenue.sql {{ config( materialized='incremental', unique_key='revenue_date', incremental_strategy='merge' ) }} SELECT DATE(order_date) AS revenue_date, SUM(order_amount) AS daily_revenue, COUNT(DISTINCT customer_id) AS unique_customers FROM {{ ref('stg_orders') }} WHERE order_status = 'completed' {% if is_incremental() %} AND order_date > (SELECT MAX(revenue_date) FROM {{ this }}) {% endif %} GROUP BY DATE(order_date) ``` `is_incremental()`ブロックはインクリメンタルビルド時のみ実行される。フルリフレッシュ(`dbt run --full-refresh`)ではスキップされ、テーブル全体が再構築される。 ## 各レイヤーでのデータ品質テスト dbtには2種類のテストが用意されている。YAMLで宣言する**ジェネリックテスト**と、失敗時に行を返すスタンドアロンSQLファイルとして記述する**シングルテスト**である。 ジェネリックテストは構造的な制約を検証する。 ```yaml # models/staging/_stg_models.yml version: 2 models: - name: stg_orders columns: - name: order_id tests: - unique # 注文IDの重複なし - not_null # 全行に注文IDが存在 - name: order_status tests: - accepted_values: values: ['completed', 'pending', 'cancelled', 'refunded'] - name: customer_id tests: - not_null - relationships: # 参照整合性チェック to: ref('stg_customers') field: customer_id ``` シングルテストは、ジェネリックテストでは表現できないビジネスルールを検証する。 ```sql -- tests/assert_revenue_never_negative.sql -- 日次収益がマイナスの行を返す(0行が期待値) SELECT revenue_date, daily_revenue FROM {{ ref('fct_daily_revenue') }} WHERE daily_revenue < 0 ``` **ユニットテスト**はdbt 1.8で導入された機能であり、制御された入力と期待される出力で変換ロジックを検証する。ウェアハウスへの接続は不要で、dbtのテストフェーズで直接実行される。 テスト戦略はデータフローに沿って構成すべきである。ソースレベルの鮮度チェックと行数検証、Stagingレベルのスキーマテスト(`not_null`、`unique`)、Intermediateレベルの参照整合性、Martレベルのビジネスロジックアサーションという順序が推奨される。 ## dbt Core v1.10とFusionエンジン dbt Core v1.10では、`run`および`build`コマンド向けに`--sample`フラグが導入された。このフラグは`ref()`と`source()`に時間ベースのサンプリングを適用し、フルビルドのコストをかけずにデータのサブセットで変換を検証できる。数十億行のファクトテーブルを持つモデルの開発イテレーションに有効である。 [dbt Fusionエンジン](https://docs.getdbt.com/docs/dbt-versions/cloud-release-tracks)はRustで一から再構築されたもので、dbt CloudのSnowflake、BigQuery、Redshift、Databricks環境において新規プロジェクトのデフォルトとなった。Fusionはセマンティックバージョニング(2.0から開始)を導入し、コンパイルと実行の両方でパフォーマンスを大幅に向上させている。 2026年のその他の注目すべき追加機能として、一元的なメトリクス定義のためのSemantic Layer YAML仕様、モデルごとのウェアハウスコンピュートを見積もるCost Insights(ベータ版)、そしてネイティブプライベートパッケージの一般提供が挙げられる。 ## マクロとJinjaによる再利用可能なロジック 同じSQLパターンが複数のモデルで繰り返される場合、[マクロ](https://docs.getdbt.com/docs/build/jinja-macros)として抽出する。マクロは`macros/`ディレクトリに格納されるJinja関数である。 ```sql -- macros/cents_to_dollars.sql {% macro cents_to_dollars(column_name) %} ROUND(CAST({{ column_name }} AS DECIMAL(10, 4)) / 100, 2) {% endmacro %} ``` 任意のモデルから呼び出せる。 ```sql -- models/staging/stg_payments.sql SELECT payment_id, order_id, {{ cents_to_dollars('amount_cents') }} AS amount_dollars, payment_method FROM {{ source('stripe', 'payments') }} ``` これによりコードベースのDRY原則が保たれる。変換式を必要なすべてのモデルにコピーする代替手段は、保守コストの増大と不整合の原因となる。 ## データエンジニアリング面接で実際に問われる質問 2026年のデータエンジニアリング面接では、基礎的な知識にとどまらないdbtの理解が問われる傾向にある。以下は、[モダンデータスタック](/technologies/data-engineering)を採用する企業の採用パターンから抽出した、候補者を差別化する質問である。 **Q:インクリメンタルモデルが夜間に全テーブルを再処理した。原因は何か?** 最も一般的な原因は、`unique_key`カラムにNULLが含まれていたことである。dbtがNULLキーでMERGEを実行すると、すべての行でマッチが失敗し、重複挿入が発生する。2番目の原因は、`dbt run --full-refresh`が意図せず実行されたケースである。このコマンドはテーブルをゼロから再構築する。3番目の原因は、`is_incremental()`フィルタがターゲットテーブルにまだ存在しないカラムを参照しているケース(初回実行と2回目以降で挙動が異なる)である。デバッグは`target/compiled/`のコンパイル済みSQLの確認から始まる。 **Q:本番dbtプロジェクトでテストをどのように階層化すべきか?** ソースの鮮度チェックが最初に実行される。ソースが更新されていなければ、下流モデルは古いデータで実行すべきではない。Stagingのテストではスキーマ制約(主キーの`unique` + `not_null`、許容値、型キャスト)を検証する。Intermediateのテストでは結合間の参照整合性を確認する。Martのテストではビジネス不変条件(収益 >= 0、アクティブユーザー数 >= 課金ユーザー数、部分の合計 = 全体)をアサートする。すべてのテストはプルリクエスト時にdev環境のスキーマに対してCIで実行し、デプロイ後は本番環境でアラート付きで再実行する。 **Q:モデルをephemeralにすべき場合とviewにすべき場合の使い分けは?** ephemeralモデルはSQLをCTEとして消費モデルにインライン化する。独立してクエリする必要のない再利用ロジックに適している。viewは読み取り時に計算され、クエリ可能なオブジェクトとして存在する。トレードオフとして、ephemeralモデルは直接テストできず(アサーションを実行するテーブルが存在しない)、データリネージツールにも表示されない。内部的なヘルパーロジックにはephemeralを、独立したテストやモニタリングが必要なものにはviewを使用する。 **Q:`source()`と`ref()`の違いを説明せよ。** `source()`は`sources.yml`ファイルで定義された生テーブルを指す。これらはdbtが管理しないテーブルである。`ref()`は他のdbtモデルを指す。両方ともDAGの依存関係を登録するが、`source()`は鮮度チェック(`dbt source freshness`)も有効にする点が`ref()`との違いである。生テーブルには`source()`を、それ以外には`ref()`を使うことは任意ではなく、dbtが管理対象と非管理対象を区別するための仕組みである。 より広範な[データエンジニアリング面接の質問](/blog/data-engineering/data-engineering-interview-questions-2026)については、[ETL vs ELTパイプラインアーキテクチャ](/blog/data-engineering/etl-vs-elt-data-pipeline-architecture)などのトピックも含め、SharpSkillの[dbt基礎](/technologies/data-engineering/interview-questions/dbt-fundamentals-de)や[dbt応用パターン](/technologies/data-engineering/interview-questions/dbt-advanced-de)のインタラクティブ演習で網羅的に学習できる。 ## まとめ - dbtはSQL SELECT文をDDLに自動コンパイルし、ウェアハウス内の生データを変換する。Staging/Intermediate/Martのレイヤー構造により、各モデルは単一の責務に集中できる - `ref()`関数は依存関係管理の要であり、テーブル名の解決とDAGの構築による実行順序の制御を担う - インクリメンタルマテリアライゼーションは大規模テーブルのコストを削減するが、`unique_key`、NULL値、`is_incremental()`フィルタの慎重な取り扱いが求められる - テストはデータフローに沿って構成する。ソースの鮮度チェック、Stagingでのスキーマ制約、Intermediateでの参照整合性、Martでのビジネスロジックアサーションの順序が推奨される - dbt Core v1.10は高速なイテレーションのための`--sample`フラグを導入し、Fusionエンジン(Rustベース、バージョン2.0)がdbt Cloudのデフォルトとなった - dbtに関する面接質問は定義の暗記ではなく、実際の障害のデバッグ(インクリメンタル再処理、NULLキー、陳腐化したソース)に焦点を当てている。コンパイル済みSQLとCIパイプラインの実践経験が重要視される --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/ja/blog/data-engineering/dbt-data-transformations-testing-interview-2026