はじめに
dbtでデータパイプラインを構築していると、テストの定義が必要になります。dbtにはテスト機能が組み込まれており、not_null や unique といったテストを schema.yml に書くだけでデータ品質のチェックを自動化できます。
しかし、「とりあえず主キーに not_null と unique を付けておけばOK」というアプローチでは、品質管理として不十分です。なぜなら、テーブルの種類によって守るべき品質の観点が異なる からです。
この記事では、データエンジニアリングにおける代表的な2種類のテーブル、トランザクションテーブル と マスターテーブル に焦点を当て、それぞれで重視すべき品質チェックの違いを整理します。
トランザクションテーブルとマスターテーブルの違い
品質チェックの話に入る前に、両者の基本的な性質の違いを押さえておきましょう。
トランザクションテーブルとは
トランザクションテーブルは、ビジネス上の 「出来事」 を記録するテーブルです。注文、決済、クリック、ログインなど、時間の流れとともに次々と発生するイベントが蓄積されます。
例:orders(注文)、payments(決済)、page_views(ページ閲覧)、login_history(ログイン履歴)
-- トランザクションテーブルの例:注文テーブル
select * from orders;
| order_id | customer_id | order_date | amount | status |
|---|---|---|---|---|
| 10001 | C001 | 2024-06-01 | 3500 | completed |
| 10002 | C002 | 2024-06-01 | 1200 | completed |
| 10003 | C001 | 2024-06-02 | 8900 | pending |
マスターテーブルとは
マスターテーブルは、ビジネスにおける 「状態」や「定義」 を管理するテーブルです。顧客、商品、部署、地域コードなど、業務の基盤となるエンティティの情報を持ちます。
例:customers(顧客)、products(商品)、departments(部署)、country_codes(国コード)
-- マスターテーブルの例:顧客テーブル
select * from customers;
| customer_id | customer_name | plan | region | |
|---|---|---|---|---|
| C001 | 田中太郎 | tanaka@example.com | premium | 東京 |
| C002 | 鈴木花子 | suzuki@example.com | standard | 大阪 |
両者の性質の違い
| 観点 | トランザクションテーブル | マスターテーブル |
|---|---|---|
| 記録するもの | 出来事(イベント) | 状態(エンティティの定義) |
| レコードの増え方 | 日々大量に追加される | 少しずつ追加・更新される |
| 更新の頻度 | 基本的に追記のみ(Append) | 既存レコードが更新される |
| レコード数の規模 | 数百万〜数億件 | 数千〜数十万件 |
| 1レコードの意味 | 「いつ・誰が・何をした」 | 「〇〇とは何か」 |
この性質の違いが、品質管理で注目すべきポイントの違いにつながります。
マスターテーブルで重視すべき品質チェック
マスターテーブルは下流のトランザクションデータと結合(JOIN)される「基盤」です。マスターの品質が崩れると、パイプライン全体に影響が波及します。
一意性(主キーの重複がないか)
マスターテーブルにおける最も基本的かつ最も重要なチェックです。主キー(customer_id や product_id など)に重複があると、JOINの結果が膨張し、集計値がずれるという深刻な問題を引き起こします。
-- 重複がある場合のJOIN膨張の例
-- customers に customer_id = 'C001' が2行あると…
select
o.order_id,
o.amount,
c.customer_name
from orders o
left join customers c on o.customer_id = c.customer_id;
-- → C001の注文が2行に増える(金額が二重計上される)
マスターテーブルの主キー重複は、下流のすべての集計結果を狂わせます。unique テストは最優先で設定しましょう。
完全性(欠落レコードがないか)
「存在すべきレコードが欠けていないか」のチェックです。例えば、全47都道府県のマスターなのに46件しかない、取り扱い商品が100件あるはずなのに95件しかない、といった状況を検知します。
レコード数の期待値がある程度わかっている場合は、件数の下限チェックが有効です。
鮮度(更新されるべきものが更新されているか)
マスターテーブルはトランザクションに比べて更新頻度が低いため、「更新されていないこと自体に気づきにくい」という特徴があります。ETL処理が止まっていたり、ソースシステム側で問題が起きていても、レコード数が変わらないため見過ごされがちです。
updated_at や loaded_at カラムが一定期間以上更新されていない場合にアラートを出す仕組みが重要です。
参照整合性(コードやカテゴリが定義済みの値か)
マスターテーブルに含まれるコード値やカテゴリが、想定された値の範囲内に収まっているかのチェックです。
例えば、plan カラムに premium、standard、free の3種類しかないはずなのに、premmium(タイポ)や trial(未定義の値)が混入していないかを確認します。
レコード数の急変(意図しない大量削除・追加がないか)
マスターテーブルのレコード数は、通常大きく変動しません。急に大量のレコードが追加されたり削除されたりした場合は、ETL処理のバグやソースシステムの問題が疑われます。
前回実行時との件数差分を監視し、閾値を超えたらアラートを出す仕組みが有効です。
トランザクションテーブルで重視すべき品質チェック
トランザクションテーブルは日々大量のレコードが追加されるため、マスターとは異なる観点での品質管理が必要です。
ボリューム異常(件数が極端に増減していないか)
トランザクションテーブルでは、日々のレコード件数にある程度の規則性があります。平日は1日5万件前後の注文があるのに、突然500件に減っていたり、50万件に増えていたりする場合は、何か問題が起きている可能性があります。
チェックの方法としては、前日比や過去7日間の平均との比較が一般的です。
-- 当日の件数が前日比50%未満なら異常とみなすイメージ
select
count(*) as today_count,
lag(count(*)) over (order by order_date) as yesterday_count
from orders
group by order_date
遅延・欠損(期待する期間のデータが届いているか)
「今日の日付のデータがまだ届いていない」「昨日の18時以降のデータが欠けている」といった遅延や欠損を検知します。
ソースシステムからのデータ連携が遅延している場合や、バッチ処理が途中で失敗している場合に発生します。
-- 最新データの日時をチェック
select max(created_at) as latest_record
from orders;
-- → これが期待する日時より古ければ遅延の可能性
値の範囲(金額がマイナス、数量が異常値でないか)
トランザクションテーブルの数値カラムには、ビジネス上あり得ない値が混入することがあります。
- 注文金額が マイナス になっている(返品処理の混入など)
- 数量が 0件 の注文レコードがある
- 金額が 異常に大きい(桁違いのデータ、単位の不一致など)
-- ビジネス上あり得ない値の例
| order_id | amount | quantity |
|----------|----------|----------|
| 10004 | -500 | 1 | -- マイナス金額
| 10005 | 9999999 | 1 | -- 異常に大きい
| 10006 | 100 | 0 | -- 数量0
外部キーの整合性(存在しないマスターを参照していないか)
トランザクションテーブルの customer_id や product_id が、対応するマスターテーブルに存在するかのチェックです。
マスターに存在しない外部キーがあると、JOINの結果が NULL になり、集計から漏れたり、レポートの値がずれたりします。
-- マスターに存在しない customer_id を持つ注文
select o.order_id, o.customer_id
from orders o
left join customers c on o.customer_id = c.customer_id
where c.customer_id is null;
この問題は「マスターの登録が遅れている」「ソースシステム間でIDの同期がずれている」といった原因で発生しがちです。
重複イベント(同一トランザクションの二重取り込みがないか)
ETL処理のリトライやソースシステムの不具合により、同一トランザクションが重複して取り込まれることがあります。
マスターテーブルの unique テストとは目的が異なります。マスターでは「同一エンティティの重複」を防ぐのに対し、トランザクションでは「同一イベントの二重取り込み」を検知します。
トランザクションテーブルの主キーに unique テストを付けることも重要ですが、そもそもトランザクションの主キーが何であるかを正しく理解する必要があります。order_id だけで一意なのか、order_id + line_item_id の複合キーなのかは、ビジネスの仕様によって異なります。
比較表で整理する
テーブル種別ごとに重視すべき品質チェックを一覧にまとめます。
| チェック項目 | マスターテーブル | トランザクションテーブル |
|---|---|---|
| 主キーの一意性 | ◎ 最重要 | ○ 重要(複合キーに注意) |
| NOT NULL | ○ 主要カラムに適用 | △ 必須カラムに限定 |
| レコード数の急変 | ◎ 急変は異常の兆候 | ○ 日次のボリューム監視 |
| 値の範囲チェック | △ コード値の範囲 | ◎ 金額・数量の異常検知 |
| 参照整合性(accepted_values) | ◎ カテゴリ・コード値 | △ ステータス値など |
| 外部キーの整合性 | △ 他マスターとの関係 | ◎ マスター参照の整合性 |
| 鮮度チェック | ◎ 更新停止に気づきにくい | ○ 遅延・欠損の検知 |
| 重複イベントの検知 | — | ◎ 二重取り込みの防止 |
| ボリューム異常 | ○ 急な増減 | ◎ 日々の件数の規則性 |
◎ = 特に重要、○ = 重要、△ = 場合による、— = 該当しにくい
よくある失敗パターン
マスターに unique を付け忘れて下流のJOINが膨張する
最もよくあり、かつ影響が大きい失敗です。マスターテーブルの主キーに重複があると、JOINの結果が意図せず行数が増え、売上の二重計上や顧客数の過大カウントにつながります。
【正常な状態】
orders (3行) × customers (一意) → 結果 3行
【マスターに重複がある場合】
orders (3行) × customers (C001が2行) → 結果 4行 ← 膨張!
この問題の厄介なところは、エラーにならない ことです。SQLは正常に実行され、結果の行数が増えていることに気づかないまま、誤った集計値がダッシュボードに反映されます。
マスターテーブルの主キーには、必ず unique テストを設定してください。これは最もコストパフォーマンスの高い品質チェックです。
トランザクションのボリューム異常を見逃してレポートが壊れる
ソースシステムの障害やETL処理の失敗で、トランザクションデータの一部が欠損していても、パイプライン自体はエラーなく動いてしまうことがあります。
結果として、「今月の売上が先月の半分に見える」「特定の日のデータだけ件数が極端に少ない」といった問題がダッシュボードで発覚し、信頼を損なうことになります。
ボリュームチェック(件数の急変検知)を入れておけば、パイプラインの段階で問題に気づけます。
すべてのカラムに not_null を付けて大量のテスト失敗を招く
「品質管理を徹底しよう」と意気込んで、すべてのカラムに not_null を設定してしまうパターンです。
実際のデータでは、NULLが許容されるカラムは多く存在します。例えば、退会日(まだ退会していない顧客はNULL)、キャンペーンコード(キャンペーン利用なしの注文はNULL)、電話番号(任意入力)などです。
# ❌ すべてに not_null を付けてしまう
columns:
- name: customer_id
tests: [not_null] # ← 正しい
- name: phone
tests: [not_null] # ← 任意入力なのでNULLがあって当然
- name: campaign_code
tests: [not_null] # ← 利用なしはNULLで正常
- name: cancelled_at
tests: [not_null] # ← 退会していなければNULLで正常
テストが大量に失敗すると、チームは「テストが壊れている」と認識してテスト結果を無視するようになり、本当に重要な品質問題を見落とす原因になります。これを アラート疲れ と呼びます。
not_null は「ビジネス上、この値は必ず存在しなければならない」というカラムにだけ設定しましょう。
まとめ
トランザクションテーブルとマスターテーブルで品質管理のポイントが異なることを改めて整理します。
| テーブル種別 | 最重要チェック | 主な品質リスク |
|---|---|---|
| マスターテーブル | 主キーの一意性、参照整合性、鮮度 | JOINの膨張、不正なコード値の混入 |
| トランザクションテーブル | ボリューム異常、値の範囲、外部キー整合性 | データ欠損、異常値の混入、二重取り込み |
テストを設計するときに意識すべきことは3つです。
- テーブルの性質を理解してからテストを書く。 トランザクションとマスターでは守るべきポイントが違う
-
最もインパクトの大きいテストから始める。 マスターの
unique、トランザクションのrelationshipsとaccepted_rangeが優先 - テストは多ければいいわけではない。 アラート疲れを防ぎ、本当に重要な問題を確実に検知できる状態を目指す
データ品質は「完璧を目指す」よりも「致命的な問題を確実に防ぐ」ことが重要です。テーブルの種類に応じた適切なテスト設計で、信頼できるデータパイプラインを構築していきましょう。
最後まで読んでいただきありがとうございました。この記事が参考になりましたら、ぜひLGTMをお願いします。