第3章 データ変換とモデリング / 想定学習時間:30〜40分 / 最終確認:2026年8月

3-6. ゴールド層オブジェクト(マテリアライズドビュー・ビュー・ストリーミングテーブル)とデータ品質チェック

🎯 この節の学習目標

1. ゴールド層に置く4つのオブジェクト

メダリオンアーキテクチャの最終層であるゴールド層(3-1)は、BI・分析・ML が「そのまま使える」形でデータを提供する層です。Unity Catalog 上でその受け皿になるオブジェクトは主に4種類あり、「結果を物理的に保存するか」「更新を誰がどう行うか」で区別します。

オブジェクト結果の保存更新のされ方向いている用途
テーブル物理保存(Delta 形式)自分のジョブで書き込む(INSERT/MERGE 等)更新ロジックを完全に制御したい汎用の保存先
ビュー保存なし(クエリ定義のみ)参照のたびに元テーブルへクエリが実行される(常に最新)列の絞り込み・簡単な整形・アクセス制御の窓口。計算コストの軽いもの
マテリアライズドビュー(MV)事前計算した結果を物理保存定義に基づき Databricks が更新を管理(可能な場合は増分更新)重い集計を BI に低コスト・低遅延で提供する
ストリーミングテーブル(ST)物理保存ストリーミングソースから増分取り込み(各行を一度だけ処理する追記中心の処理)ファイルやイベントの継続的な取り込み・ストリーミング変換
🥈 シルバー層のテーブル群クリーニング・結合済み(3-1〜3-4)
集計・提供形式の選択
🥇 ゴールド層テーブル / ビュー / マテリアライズドビュー / ストリーミングテーブル
SQLウェアハウス経由など
BI ダッシュボード・分析・ML利用者は内部の変換を意識しない

図:ゴールド層のオブジェクトと利用者の関係

1-1. ビュー vs マテリアライズドビュー:計算をいつ払うか

両者の違いは「計算コストをいつ払うか」です。ビューは参照のたびに計算するため、定義が重い集計だとダッシュボードを開くたびに全計算が走ります。MV は事前に計算して保存しておくため、参照時は保存済みの結果を読むだけで高速・低コストです。しかも更新は Databricks が管理し、ソースの変化に対して可能な場合は増分更新(全再計算せず差分だけ反映)されます。

1-2. マテリアライズドビュー vs ストリーミングテーブル

どちらも「Databricks が更新を管理する」仲間ですが、役割が違います。ST は入口側(ソースからの増分取り込み。各入力行を一度だけ処理する追記中心の処理)、MV は出口側(集計・結合の結果を最新に保つ。ソースの更新・削除にも定義どおり追従)に向きます。ST は集計の作り直しをしないため、ソース側の過去データ修正を反映したい集計には MV を選びます。

💡 具体例:SQL でのゴールド層オブジェクト作成

-- ビュー:保存なし。参照のたびに元テーブルを計算
CREATE OR REPLACE VIEW gold.v_orders_recent AS
SELECT order_id, customer_id, total_amount, order_date
FROM silver.orders
WHERE order_date >= current_date() - INTERVAL 90 DAYS;

-- マテリアライズドビュー:事前計算・増分更新。BI向けの重い集計に
CREATE OR REPLACE MATERIALIZED VIEW gold.mv_daily_sales AS
SELECT
  order_date,
  region,
  SUM(total_amount)              AS revenue,
  COUNT(*)                       AS order_cnt,
  COUNT(DISTINCT customer_id)    AS customers
FROM silver.orders
GROUP BY order_date, region;

-- ストリーミングテーブル:ファイルの継続的な増分取り込み
CREATE OR REFRESH STREAMING TABLE bronze.events_st AS
SELECT * FROM STREAM read_files(
  '/Volumes/main/raw/events/',
  format => 'json'
);

MV と ST は、SQL ウェアハウスや Lakeflow Spark Declarative Pipelines(旧 Delta Live Tables)上で動く「更新を宣言的に任せる」オブジェクトです。REFRESH MATERIALIZED VIEW gold.mv_daily_sales; のように手動更新もでき、スケジュール設定で定期更新にもできます。

📝 試験のポイント

選択問題は要件のキーワードで解けます。「事前計算した集計を BI に安く・速く提供したい」→ マテリアライズドビュー。「保存せずクエリ定義だけ共有したい/常に元テーブルの最新を見たい」→ ビュー。「到着し続けるファイルを増分で取り込みたい」→ ストリーミングテーブル。「書き込みロジックを自分のジョブで完全制御」→ テーブル。「ビューは結果を物理保存する」「MV は参照のたびに全計算する」といった逆の記述は誤答です。

2. BI/分析チーム向けゴールド層の設計

ゴールド層の設計で決めるべきことは、技術よりもまず「誰が・何の質問に答えるためのデータか」です。

3. データ品質チェック

ゴールド層は利用者から最も見られる層であり、ここに不正データが混ざると信頼を直接損ないます。品質を守る仕組みは「テーブル自体に制約を付ける」「パイプラインで検査する」「クエリで監視する」の3段構えです。

3-1. テーブル制約:NOT NULL と CHECK

Delta テーブルには強制力のある制約を付けられます。制約違反の書き込みはエラーで拒否されるため、不正データがテーブルに入ること自体を防げます。

💡 具体例:制約の追加

-- NOT NULL 制約:キー列の null を拒否
ALTER TABLE gold.daily_sales
  ALTER COLUMN order_date SET NOT NULL;

-- CHECK 制約:条件を満たさない行の書き込みを拒否
ALTER TABLE gold.daily_sales
  ADD CONSTRAINT valid_revenue CHECK (revenue >= 0);

ALTER TABLE silver.orders
  ADD CONSTRAINT valid_date
  CHECK (order_date >= '2020-01-01');

制約を追加する時点で既存データも条件を満たしている必要があります(違反行が既にあると ALTER 自体が失敗します)。また、違反時はトランザクションごと失敗するため、「不正行だけ落として処理は続けたい」用途には次の expectations が向きます。

3-2. パイプラインの expectations(Lakeflow Spark Declarative Pipelines)

Lakeflow Spark Declarative Pipelines(旧 Delta Live Tables)では、expectations(期待値)という宣言的な品質ルールを定義できます。テーブル制約と違い、違反時の動作を3種類から選べるのが特徴です。

違反時の動作挙動使いどころ
warn(記録のみ)違反行も書き込まれるが、違反件数がメトリクスとして記録されるまず実態を観測したい導入期
drop(行を除外)違反行だけを捨てて処理を継続する少数の不正行は落として本流を止めたくない場合
fail(処理停止)違反があればパイプラインを失敗させる1行でも不正が許されないクリティカルなデータ
-- SQL での expectations の例(違反行を除外する場合)
CREATE OR REFRESH MATERIALIZED VIEW gold.mv_daily_sales (
  CONSTRAINT valid_date    EXPECT (order_date IS NOT NULL) ON VIOLATION DROP ROW,
  CONSTRAINT valid_revenue EXPECT (revenue >= 0)           ON VIOLATION FAIL UPDATE
) AS
SELECT ...;

3-3. 検証クエリのパターン

制約や expectations に加えて、更新後のテーブルをクエリで検証するのも実務の定番です。ジョブの最終タスクとして流し、期待に反したら通知・失敗させます。

-- パターン1:キーの一意性(重複があれば行が返る)
SELECT order_id, COUNT(*) AS cnt
FROM gold.daily_sales
GROUP BY order_id
HAVING COUNT(*) > 1;

-- パターン2:null 率の監視
SELECT
  COUNT(*)                                          AS total,
  SUM(CASE WHEN region IS NULL THEN 1 ELSE 0 END)   AS null_region
FROM gold.daily_sales;

-- パターン3:値域・鮮度のチェック
SELECT COUNT(*) FROM gold.daily_sales WHERE revenue < 0;
SELECT MAX(order_date) FROM gold.daily_sales;  -- 直近日付が来ているか

📝 試験のポイント

使い分けの軸は「違反時にどうしたいか」です。絶対に入れない→ テーブルの NOT NULL / CHECK 制約(違反は書き込みエラー)。落として続行/記録だけ/止める を選びたい→ パイプラインの expectations(warn / drop / fail)。更新後の状態を監視したい検証クエリ。「CHECK 制約は違反行を自動的にスキップして書き込みを続ける」という選択肢は誤りです(制約はトランザクションを失敗させます)。

✅ この節のまとめ

練習問題

問1. 数億行のシルバーテーブルに対する重い集計結果を、BI ダッシュボードに低コスト・低遅延で提供したい。ソーステーブルは日次で更新される。最も適切なオブジェクトはどれか。

  1. ビュー
  2. マテリアライズドビュー
  3. ストリーミングテーブル
  4. 一時ビュー(temporary view)
解答と解説を見る

正解:B

「事前計算した集計を安く速く提供」はマテリアライズドビューの典型ユースケースです。結果が物理保存されるため参照時は読むだけで済み、ソースの日次更新には(可能な場合)増分更新で追従します。Aのビューは参照のたびに数億行の集計が走り、ダッシュボードを開くたびに高コストです。Cは増分取り込み向けで、ソースの更新を反映する集計の作り直しをしません。Dはセッション限りで消えるため、BI への継続提供には使えません。

問2. ビューとマテリアライズドビューの違いの説明として正しいものはどれか。

  1. ビューは結果を物理保存し、マテリアライズドビューは保存しない
  2. ビューは参照のたびに定義クエリが実行され、マテリアライズドビューは事前計算された結果を読む
  3. どちらも結果を物理保存するが、ビューの方が高速である
  4. マテリアライズドビューは参照のたびに必ず全件を再計算する
解答と解説を見る

正解:B

ビュー=保存なし・参照時計算(常に最新だが毎回コストを払う)、MV=事前計算・物理保存(参照は安いが更新タイミングに依存)という関係です。Aは両者が逆です。Cはビューが保存する前提が誤りです。Dについて、MV の再計算は参照時ではなく更新時に行われ、しかも可能な場合は増分更新で差分のみ反映されます。

問3. ゴールドテーブル gold.daily_salesrevenue 列に負の値が書き込まれることを、テーブルレベルで確実に拒否したい。適切な方法はどれか。

  1. ALTER TABLE gold.daily_sales ADD CONSTRAINT valid_revenue CHECK (revenue >= 0) を実行する
  2. ダッシュボード側で負の値を表示しないフィルタを設定する
  3. SELECT COUNT(*) FROM gold.daily_sales WHERE revenue < 0 を毎朝手動で実行する
  4. 列名を revenue_positive に変更して負の値が入らないことを明示する
解答と解説を見る

正解:A

CHECK 制約は強制力を持ち、違反する書き込みはトランザクションごとエラーで拒否されるため、「テーブルレベルで確実に拒否」という要件に合致します。Bは表示を隠すだけでデータ自体は汚染されます。Cは検知(それも手動)であって拒否ではなく、発見までの間に不正データが利用されえます。Dは名前を変えても何の強制力もありません。なお制約追加時には既存データが条件を満たしている必要がある点も覚えておきましょう。

問4. Lakeflow Spark Declarative Pipelines(旧 Delta Live Tables)の expectations で、「不正な行だけを除外し、パイプラインの処理自体は継続したい」。違反時の動作として適切なものはどれか。

  1. 違反を記録するだけで、違反行もそのまま書き込む(warn)
  2. 違反行を除外して処理を継続する(ON VIOLATION DROP ROW)
  3. 違反があった時点でパイプラインを失敗させる(ON VIOLATION FAIL UPDATE)
  4. expectations では違反行の除外はできないため、書き込み後に DELETE 文で削除する
解答と解説を見る

正解:B

expectations は違反時の動作を選択でき、「不正行の除外+処理継続」は DROP ROW の役割そのものです。Aの warn は違反行も書き込まれてしまうため「除外したい」要件を満たしません。Cの fail は処理全体が止まるため「継続したい」要件に反します。Dは誤りで、除外は expectations の標準機能です。書き込み後の DELETE は不正データが一時的に見えてしまう点でも劣ります。