dbt の relationships テストは、ファクト側の外部キー列にある値が、ディメンション側の主キー列にも必ず存在することを検証します。これは DWH 上で物理的な外部キー制約を張らない設計でも、論理的な参照整合性を保つための重要な仕組みです。
本稿では、定義方法、実務での使い分け、性能・運用の勘所、そして Analytics Engineer 試験で問われやすいポイントを、公式ドキュメントの挙動に基づいて解説します。
relationships は、子テーブルの列値が親テーブルの列に存在するかを検証します。子側の NULL は既定で無視され、違反は「子に値があるが親に存在しない」ケースのみ検出されます。
dbt はテスト用のクエリを生成して差分だけを返すため、テストは read-only であり、DWH に物理的な制約を作成しません。
| テスト種別 | 検証観点 | 代表的な失敗例 |
|---|---|---|
| relationships | 参照整合性 | fact.customer_id=999 が dim に存在しない |
| not_null | 欠損有無 | fact.customer_id が NULL |
| unique | 一意性 | dim.customer_id に重複がある |
基本関係のイメージ
最小構成の schema.yml 例
version: 2
models:
- name: fact_orders
columns:
- name: customer_id
tests:
- relationships:
to: ref('dim_customers')
field: id
テスト対象を期間や状態で絞りたい場合、generic テストの where 設定が有効です。実行環境ごとに条件を切り替えることで、開発環境の小さなサンプルにも本番相当の整合性検証を適用できます。
複合キーの参照整合性は relationships 単体では直接サポートされません。その場合は、親子双方で連結キーを作るか、単一の singular テスト(SQL)で NOT EXISTS を書くのが実務的です。
| 設定項目 | 意味 | 注意点 |
|---|---|---|
| to | 参照先モデルを指定 | 通常は ref('parent_model') を使う |
| field | 参照先の列名 | 親側のキー列と一致させる |
| where | 子側の絞り込み条件 | 重いテーブルは期間絞りで短縮 |
where で子集合を絞る流れ
where を併用した relationships
version: 2
models:
- name: fact_orders
columns:
- name: customer_id
tests:
- relationships:
to: ref('dim_customers')
field: id
where: "order_date >= dateadd(day, -90, current_date) AND order_status <> 'CANCELLED'"
relationships は内部的に NOT EXISTS や LEFT ANTI JOIN 相当のクエリになります。大規模データでの高速化には、結合キー列の物理設計と絞り込みが有効です。
Snowflake ではクラスタリングキー、Databricks では Z-Ordering など、基盤ごとの最適化を組み合わせてテスト時間を短縮します。
| 基盤 | 推奨チューニング | 補足 |
|---|---|---|
| Snowflake | クラスタリングキー on 親.id / 子.customer_id | Micro-partition の分布を意識 |
| Databricks | Z-ORDER on 結合キー列 | Delta テーブルのスキップ効率向上 |
| 共通 | 期間絞り込み + 必要列のみ参照 | SELECT 列最小化で I/O を削減 |
テスト時の論理計画イメージ(抽象化)
複合キーを singular テストで検証する SQL 例
-- tests/relationships_orders_customers.sql
-- 子: fact_orders(order_id, customer_id)
-- 親: dim_customers(customer_id, tenant_id)
select f.order_id, f.customer_id, f.tenant_id
from {{ ref('fact_orders') }} f
where f.customer_id is not null
and not exists (
select 1
from {{ ref('dim_customers') }} d
where d.customer_id = f.customer_id
and d.tenant_id = f.tenant_id
)
失敗行の調査には store_failures が便利です。テスト実行時に違反レコードを専用スキーマに永続化でき、再現・共有が容易になります。
重大度は severity で制御します。開発では warn、本番パイプラインのゲートでは error とする運用が現実的です。
| 項目 | 例 | 動作 |
|---|---|---|
| severity | warn / error | warn は警告で継続、error は失敗で停止 |
| store_failures | true | 違反レコードをテーブルに保存 |
| 選択実行 | dbt test -s test_type:generic | generic テストのみ実行 |
失敗レコードの運用フロー
環境別に重大度と失敗保存を切り替える例
# dbt_project.yml の tests デフォルト設定例
tests:
+severity: "{{ target.name == 'prod' and 'error' or 'warn' }}"
+store_failures: "{{ target.name == 'prod' }}"
Analytics Engineer 試験では、relationships の目的、NULL の扱い、unique/not_null との役割分担、そして singular テストとの使い分けが頻出です。
実務では、親のキー健全性を unique + not_null で先に担保し、その上で relationships を流す順序が安定します。
| 観点 | よく問われるポイント | 要約 |
|---|---|---|
| 目的 | relationships が保証すること | 子の値が親にも存在すること |
| NULL | 子の NULL は失敗か | 既定では無視(失敗にしない) |
| 代替手段 | 複合キーどうするか | singular テストや連結サロゲート |
モデル層とテストの配置イメージ
サロゲートキーで relationships を単一列に寄せる例
-- 親・子双方で同じロジックのサロゲートキーを作成
-- parent_surrogate_key = md5(coalesce(customer_id,'') || '|' || coalesce(tenant_id,''))
-- schema.yml 抜粋
models:
- name: fact_orders
columns:
- name: customer_sk
tests:
- relationships:
to: ref('dim_customers')
field: customer_sk
Analytics Engineer
問題 1
fact_orders.customer_id の全ての値が dim_customers.id に存在することを dbt の generic テストで確認したい。最も適切なテストはどれか。
正解: C
relationships は子列の値が参照先モデルの指定列に存在することを検証する。not_null は欠損、unique は一意性、accepted_values は許容値集合のチェックであり参照整合性の保証には直接ならない。
relationships テストは DWH に外部キー制約を作成しますか?
いいえ。dbt のテストはクエリを実行して違反行を検出する仕組みで、物理的な制約は作成しません。
子列が NULL の場合、relationships は失敗になりますか?
既定では子側の NULL は違反に含めません。NULL も禁止したい場合は not_null を併用します。
複合キーの参照整合性はどう検証すべきですか?
relationships は単一列が前提です。複合キーは親子で同一ロジックのサロゲートキーを作成して relationships をかけるか、singular テストで NOT EXISTS を記述して検証します。
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)、設定優先度...