Zenn
Open36

【ディメンショナルモデリング】

YuichiYuichi

CUSTOMER_FRUITSでディメンションテーブルを作成するサンプル

前提条件

customer_fruits

with
    customer_fruits as (
        select *
        from
            unnest(
                array<
                    struct<
                        id int64,
                        customer_id int64,
                        fruit_id int64,
                        created_at timestamp
                    >
                >[
                    (1, 101, 1, timestamp('2024-03-01 10:00:00')),
                    (2, 102, 2, timestamp('2024-03-02 11:00:00')),
                    (3, 101, 3, timestamp('2024-03-03 12:00:00')),
                    (4, 103, 1, timestamp('2024-03-04 13:00:00')),
                    (5, 102, 3, timestamp('2024-03-05 14:00:00'))
                ]
            )
    )

select *
from customer_fruits

mst_fruit

with
    mst_fruit as (
        select *
        from
            unnest(
                array<struct<id int64, name string, deleted_at timestamp>>[
                    (1, 'りんご', null), (2, 'バナナ', null), (3, 'メロン', null)
                ]
            )
    )

select *
from mst_fruit

YuichiYuichi

customer_fruitsをdbt snapshotで実行した場合

  • 生成カラムは説明に必要なものだけにしています
  • id = 2 のレコードを物理削除が発生している
    今回は、created_atしかないテーブルで物理削除されている想定ですが、created_atとdeleted_atがあれば、dbt_valid_from→created_at、dbt_valid_to→deleted_atの置き換えで同じことができます
with
    customer_fruits_snapshot as (
        select *
        from
            unnest(
                array<
                    struct<
                        id int64,
                        customer_id int64,
                        fruit_id int64,
                        created_at timestamp,
                        dbt_valid_from timestamp,
                        dbt_valid_to timestamp
                    >
                >[
                    (
                        1,
                        101,
                        1,
                        timestamp("2024-03-01 10:00:00"),
                        timestamp("2024-03-01 10:00:00"),
                        null
                    ),
                    (
                        2,
                        102,
                        2,
                        timestamp("2024-03-02 11:00:00"),
                        timestamp("2024-03-02 11:00:00"),
                        timestamp("2025-03-06 16:00:00")
                    ),
                    (
                        3,
                        101,
                        3,
                        timestamp("2024-03-03 12:00:00"),
                        timestamp("2024-03-03 12:00:00"),
                        null
                    ),
                    (
                        4,
                        103,
                        1,
                        timestamp("2024-03-04 13:00:00"),
                        timestamp("2024-03-04 13:00:00"),
                        null
                    ),
                    (
                        5,
                        102,
                        3,
                        timestamp("2024-03-05 14:00:00"),
                        timestamp("2024-03-05 14:00:00"),
                        null
                    )
                ]
            )
    )
    
select *
from customer_fruits_snapshot

YuichiYuichi


開始日=前レコード終了日ではない方が

従業員.従業員ID =経費ファクト.従業員ID AND
経費ファクト.発生日
BETWEEN 従業員.開始日AND 従業員.終了日

でとれるから便利

YuichiYuichi
with
    mst_fruit as (
        select *
        from
            unnest(
                array<struct<id int64, name string, deleted_at timestamp>>[
                    (1, 'りんご', null), (2, 'バナナ', null), (3, 'メロン', null)
                ]
            )
    ),
    customer_fruits_snapshot as (
        select *
        from
            unnest(
                array<
                    struct<
                        id int64,
                        customer_id int64,
                        fruit_id int64,
                        created_at timestamp,
                        dbt_valid_from timestamp,
                        dbt_valid_to timestamp
                    >
                >[
                    (
                        1,
                        101,
                        1,
                        timestamp("2024-03-01 10:00:00"),
                        timestamp("2024-03-01 10:00:00"),
                        null
                    ),
                    (
                        2,
                        102,
                        2,
                        timestamp("2024-03-02 11:00:00"),
                        timestamp("2024-03-02 11:00:00"),
                        timestamp("2025-03-06 16:00:00")
                    ),
                    (
                        3,
                        101,
                        3,
                        timestamp("2024-03-03 12:00:00"),
                        timestamp("2024-03-03 12:00:00"),
                        null
                    ),
                    (
                        4,
                        103,
                        1,
                        timestamp("2024-03-04 13:00:00"),
                        timestamp("2024-03-04 13:00:00"),
                        null
                    ),
                    (
                        5,
                        102,
                        3,
                        timestamp("2024-03-05 14:00:00"),
                        timestamp("2024-03-05 14:00:00"),
                        null
                    )
                ]
            )
    ),

    mst_fruit_string as (
        select
            id as fruit_id,
            concat(lpad(cast(id as string), 2, '0'), "_", name) as fruit_name,
            deleted_at
        from mst_fruit
    ),

    customer_fruit_period as (
        select
            customer_fruits_snapshot.customer_id,
            customer_fruits_snapshot.fruit_id,
            date(
                datetime(customer_fruits_snapshot.dbt_valid_from, 'Asia/Tokyo')
            ) as valid_from,
            date(
                coalesce(
                    datetime(customer_fruits_snapshot.dbt_valid_to, 'Asia/Tokyo'),
                    '9999-12-31'
                )
            ) as valid_to
        from customer_fruits_snapshot
    ),

    calendar as (
        select create_date
        from
            unnest(
                generate_date_array(
                    (select min(valid_from) from customer_fruit_period),
                    date_add(current_date('Asia/Tokyo'), interval 1 month),
                    interval 1 day
                )
            ) as create_date
    ),

    fruit_calendar_mapping as (
        select
            calendar.create_date,
            customer_fruit_period.customer_id,
            customer_fruit_period.fruit_id,
            mst_fruit_string.fruit_name
        from customer_fruit_period
        left join mst_fruit_string using (fruit_id)
        left join
            calendar
            on calendar.create_date
            between customer_fruit_period.valid_from and customer_fruit_period.valid_to
    ),

    daily_fruit_aggregation as (
        select
            customer_id,
            create_date,
            array_agg(distinct fruit_id order by fruit_id asc) as fruit_ids,
            array_agg(distinct fruit_name order by fruit_name asc) as fruit_names,

        from fruit_calendar_mapping
        group by 1, 2
    ),

    final as (
        select
            customer_id,
            fruit_ids,
            array_to_string(
                array(select cast(x as string) from unnest(fruit_ids) as x), ','
            ) as fruit_id_strings,
            array(
                select regexp_replace(y, '.._', '') from unnest(fruit_names) as y
            ) as fruit_names,
            regexp_replace(
                array_to_string(fruit_names, ','), '.._', ''
            ) as fruit_names_string,
            min(create_date) as valid_from,
            if(
                max(create_date)
                = date_add(current_date('Asia/Tokyo'), interval 1 month),
                date('9999-12-31'),
                max(create_date)
            ) as valid_to,
            max(create_date)
            = date_add(current_date('Asia/Tokyo'), interval 1 month) as is_current
        from daily_fruit_aggregation
        group by 1, 2, 3, 4, 5
    )

select *
from final
order by 1, 6

YuichiYuichi

https://amzn.asia/d/jgg0G32

パートI 基礎

  • 本書では、列名に「_key」という接尾辞を付けることで、代理キーを簡単に識別できます。顧客ディメンションの代理キーはcustomer_key、営業担当ディメンションの代理キーはsalesperson_keyというように呼ばれています。ディメンションテーブルの代理キーは常に最初の属性として示されています。
  • 代理キーと自然キーを分離することで、元の運用システムが変更を追跡できない場合でも、データ ウェアハウスで変更を追跡できます。

さらに読む

  • 業務システムの設計に関する詳細な情報については、Chris Date著『データベースシステム入門 第8版』(Addison Wesley、2003年)に勝る優れた参考文献はありません。本書は、リレーショナルデータベース管理システムにおけるトランザクション処理をサポートするために用いられる正規化の原則を詳細に解説しています。
  • 業務システムと分析システムの違いについては、豊富な情報が公開されています。
    • まずは、Ralph KimballとMargy Ross共著の『The Data Warehouse Toolkit, Second Edition』 (Wiley、2002年)の第1章
    • Inmon、Imhoff、Sousa共著の『The Corporate Information Factory, Second Edition』(Wiley、2000年)の解説から始めるのが良いでしょう。
    • ファクトとディメンションの分離に関する詳細については、ディメンション設計に関する書籍を参照してください。
      • 『Data Warehouse Design Solutions』(Adamson and Venerable、Wiley、1995年)と
      • 『Mastering Data Warehouse Aggregates』(Adamson、Wiley、2006年)はどちらも冒頭でこのトピックを取り上げており、
      • KimballとRossの『The Data Warehouse Toolkit』も同様です。これらの書籍では、スタースキーマの典型的なクエリパターンについても取り上げています。
      • ブラウズクエリについては、『The Data Warehouse Toolkit』で解説されています。

第2章 データウェアハウスアーキテクチャ

  • WH Inmonのアーキテクチャ
    • コーポレート・インフォメーション・ファクトリー・アーキテクチャ
  • Kimballのアーキテクチャ
    • 本書では、Kimballのアーキテクチャをディメンション・データウェアハウス・アーキテクチャと呼びます。
  • スタンドアロン・データマート
    • エンタープライズ・コンテキストで設計されていない分析データストア
    • 短期的な節約は、長期的なコストの増加につながります
    • 将来の潜在的なコストについて共通の理解がある限り、特定の分野に特化することは理にかなっているかも

本書で使用されている用語

データウェアハウス

  • スタンドアロンのデータマートを含む分析データベースを含むあらゆるソリューションを指します。この用語は、中央リポジトリや統合リポジトリを意味するものではありません。

エンタープライズ・データウェアハウス

  • コーポレート・インフォメーション・ファクトリーの中央リポジトリを指します。この用語の使用は、他のデータウェアハウス・アーキテクチャがエンタープライズ志向に欠けていることを意味するものではありません。

データマート

  • あらゆるアーキテクチャにおける特定の領域を指します。この用語の使用は、特定の部門に焦点を絞ったり、企業全体のコンテキストが欠如していることを意味するものではありません。

ETL

  • 構造化データストア間で情報を移動するあらゆるアクティビティを指します。この用語を一般的な意味で使用することは、より具体的な定義を持つCorporate Information Factoryを軽視する意図はありません。

ソースシステム

  • スタースキーマがデータを取得するコンピュータシステムを指します。企業情報ファクトリーのデータマートの場合、ソースシステムはエンタープライズデータウェアハウスです。ディメンション型データウェアハウスまたはスタンドアロンデータマートのスタースキーマの場合、ソースシステムはオペレーショナルシステムです。

ビジネスインテリジェンス

  • エンドユーザー向けのレポートやその他の情報製品を作成するために使用されるあらゆるソフトウェア製品を指すために使用されます。これは、独立した分析データストアや、特定の形式のパッケージソフトウェアの使用を意味するものではありません。
YuichiYuichi

ディメンション

ディメンションとその値はさまざまな方法で意味を追加します。

  • クエリやレポートをフィルタリングするために使用されます。
  • ファクトの集約範囲を制御するために使用されます。
  • 情報を整理したり並べ替えたりするために使用されます。
  • レポートの背景情報を提供するために事実を添えます。
  • マスター詳細構成、グループ化、小計、および要約を定義するために使用されます。

ファクト

ファクトテーブルには単価(unit_price)ではなく、数量×単価である金額(order_dollars)を格納すべき。
その理由は以下の通り:

  • クエリ時の計算が不要でパフォーマンスが向上
  • 単価変更による影響を避け一貫性を確保
  • 金額は完全加算可能で、柔軟な集計が可能
  • 単価はディメンションとして使い、金額はファクトとして保持する

単位量は分析において重要なディメンション。単位量を格納できる明確なディメンションテーブルがない場合は、ファクトテーブルに縮退ディメンションとして配置することができます。

完全加算可能(fully additive)」とは、どんな切り口(ディメンション)で集計しても合計できる指標のことです。


🔁 具体例:

たとえば order_dollars(売上金額) が完全加算可能な場合:

  • 日別に合計:OK
  • 商品別に合計:OK
  • 店舗別に合計:OK
  • これらを組み合わせても合計可能(例:店舗×日別売上)

⚠️ 対して、非加算可能なものの例:

  • 単価(unit_price) → 平均は出せるけど、足しても意味がない
  • 在庫残数(inventory_balance) → 時点ごとの値なので、合計するとおかしくなる

つまり、「完全加算可能」=どんな集計軸でも素直に足し算できる指標という意味です。データモデリングではとても重要な性質

加算可能な値を保存する

比率そのものはファクトテーブルに保存せず、その構成要素である「利益額(margin_dollars)」と「売上額(order_dollars)」を格納します。これらはどちらも**完全加算可能(fully additive)**なので、どんなディメンション(商品別・日別など)で集計しても正しい合計値が得られます。

  • 比率はファクトテーブルに直接格納しない。
  • 加算可能な構成要素を格納し、必要に応じて比率を計算する。

「ファクトテーブルの粒度は、可能な限り細かく設定せよ」

例外: 別途、詳細データを保存したリポジトリ(例:データレイクや履歴テーブル)がある場合は、
→ ファクトテーブルは集計済み(粗い粒度)でもよい場合がある。

YuichiYuichi

🧩 縮退ディメンションとは?

通常はディメンション(属性)は別テーブルに分離されますが、
どうしても分けにくい属性をファクトテーブルに直接持たせた場合、
それを「縮退ディメンション」と呼びます。


✅ 特徴

  • ファクトテーブルに含まれるが、役割はディメンション
    • フィルター、グルーピング、並び替えなどに使える。
    • 例:注文番号、伝票番号、トランザクションIDなど
  • ディメンションテーブルと違って、参照テーブルが存在しない

🧱 なぜ使うのか?

  • 一部の属性は他と共有されず、独自の値しか持たない(例:トランザクションID)
  • わざわざディメンションテーブルを作っても意味がないか、正規化しにくい

⚠️ 注意点

  • 文字列のような情報を多く含む場合、ファクトテーブルが重くなる
  • むやみに使うと、パフォーマンスや保守性に悪影響が出る
  • 多くの場合は、**ジャンクディメンション(複数の小さい属性をまとめたテーブル)**の方が適切

💡 実務での使いどころ

  • **トランザクション識別子(例:order_id, invoice_number)**など、
    それ自体で分析には使わないが、詳細のトレースやマスター・ディテールの関係構築に使える属性に限って使うのが一般的。
YuichiYuichi

**スローチェンジングディメンション(SCD)**の Type 1Type 2 の違い

分析の整合性を保ちたい場合はType 2、最新情報だけが必要な場合はType 1を選ぶのが一般的です。


🔁 Type 1

  • Action(操作): ディメンションを上書き更新(Update Dimension)
  • Effect on Facts(ファクトへの影響): 履歴が上書きされる(Restates History)

→ 過去のファクトが最新のディメンション値と結びついてしまう。


🧱 Type 2

  • Action(操作): ディメンションに新しい行を追加(Insert New Row in Dimension Table)
  • Effect on Facts(ファクトへの影響): 履歴が保持される(Preserves History)

→ 過去のファクトは当時の属性値に紐付いたまま残る。


YuichiYuichi

🌟 スター・スキーマの基本まとめ

🧭 ディメンションテーブル

  • **自然キーと代替キー(サロゲートキー)**を持ち、履歴管理が可能。
  • 列数は多く(ワイドに)、分析に有用な属性を豊富に持たせる。
  • 数値型のディメンションも存在し、使用方法でファクトと区別される。
  • 正規化はせず、第3正規形にはしない
  • ジャンクディメンションは無関係な属性をまとめたもの。
  • 行動ディメンションはファクトから導出される属性群。

📊 ファクトテーブル

  • ディメンションへの外部キー+ファクト値で構成される。
  • すべての関連ファクトを含める(派生可能なものも含める)。
  • 加算できない値(比率など)は、加算可能な構成要素に分解し、レポート時に計算。
  • 疎な構造(イベント発生時のみ行が存在)。
  • **粒度(グレイン)**は明確に定義する。
  • 縮退ディメンションはファクトテーブル内にあるディメンション(例:トランザクションID)。

🐢 スローリー・チェンジング・ディメンション(SCD)

  • タイプ1:属性の変更を上書きし、履歴は保持されない(過去のファクトの文脈が変わる)。
  • タイプ2:変更時に新しい行を挿入、履歴が保持される(ファクトの履歴文脈が保たれる)。

🧊 キューブ(OLAP)

  • 多次元データベースでの実装形態、OLAP分析が可能。
  • SQLでは表現しづらい柔軟な分析ができる。
  • 属性や取引数の増加でストレージ使用量が増加
  • スケーラビリティは限定的だが、スター・スキーマを補完する強力な手段となる。
YuichiYuichi

ドリル・アクロスとは?

  • 異なるファクトテーブル間の情報を結合して分析する手法。
  • たとえば「受注ファクト」と「出荷ファクト」を連携し、「受注に対してどれだけ出荷されたか」を分析する。

✅ ファクトを組み合わせてよいか判断する2つの質問

  1. これらのファクトは同時に発生するか?
    →(例:受注日と出荷日が同じか)
  2. これらのファクトは同じ粒度(グレイン)で記録されているか?
    →(例:どちらも「注文単位」での記録か)

🛑 どちらかが「いいえ」の場合

  • 異なるプロセスを表すファクトなので、直接結合してはいけない
  • たとえば、「注文」と「出荷」は発生時点が異なり、処理単位(粒度)も異なることが多いため、**別々に集計し、あとから結合(ドリル・アクロス)**する必要がある。
YuichiYuichi

Sparsity(スパース性): ファクトテーブルに記録されているデータの「まばらさ」を表す概念です。


🔍 Sparsityの意味

  • ファクトテーブルには、実際にビジネス活動が発生したときだけ行が記録される。
  • つまり、すべてのディメンションの組み合わせが揃っているわけではない
  • 実際に存在する組み合わせは、理論上のすべての組み合わせに比べて非常に少ない

📊 例

たとえば、以下の3つのディメンションがあるとします:

  • 商品:1,000種
  • 店舗:100店舗
  • 日付:365日

理論上の組み合わせ数は 1,000 × 100 × 365 = 36,500,000行
しかし、実際に売上が発生した組み合わせはそのごく一部(例えば数百万行)しか存在しない。

→ このように、全体に対して実データがまばらに存在している状態が「スパース(sparse)」と呼ばれます。


⚠️ 実務での注意点

  • JOIN時の結合漏れやNULL処理に注意が必要。
  • BIツールやクエリで**「存在しないデータ」をどう扱うか**を意識する。
  • データ圧縮やパフォーマンスチューニングの観点でも重要。

要するに、「ファクトテーブルには必要なデータしか存在しない、そしてそれは全体の可能性に対してごく一部である」というのがSparsityの本質です。

YuichiYuichi

🐸 茹でガエルのたとえ話(boiling the frog)

  • カエルをぬるま湯に入れて、少しずつ温度を上げていくと、カエルは変化に気づかずにそのまま茹で上がってしまう(という寓話)。
  • これは、「小さな問題の積み重ねが、やがて大きな問題になる」という警鐘を鳴らす話です。

💡 ここでの教訓

  • 異なるプロセス(例:注文と出荷)に関するファクトを1つのファクトテーブルに入れてしまうと、クエリで必ず条件を追加しなければならないようになります(HAVING句など)。
SELECT product_key, SUM(quantity_shipped) FROM sales_facts
GROUP BY product_key
HAVING SUM(quantity_shipped) > 0
  • その追加作業は最初は小さく感じても、あらゆる分析で同じ対応が必要になり、最終的には大きな負担になります。
  • つまり、設計時の手抜きが、将来の分析作業の重荷になるということです。

📌 メッセージ

「クエリで何とかする」のではなく、最初のスキーマ設計で正しくプロセスを分けるべき
そうすれば後で「茹でガエル」にならずに済む。


✅ 設計時にすべきこと

  • プロセスごとに別々のファクトテーブルを作る。
  • クエリで余計なフィルタ条件を入れずに済むようにする。
  • 将来のメンテナンス性・分析の自由度を高める。

Schema design time, as my friend used to say, is your chance to “un-boil” the frog.

スキーマ設計は、私の友人がよく言っていたように、カエルを「煮る前に冷ます」チャンスです。

YuichiYuichi

ドリルアクロス (drill across)

  • 2つのファクトテーブルを直接結合したり、共通のディメンションを介して結合したりしないでください。不正確な結果が生じる可能性があります。
  • 2つのプロセスを比較する適切な方法は、「ドリルアクロス」と呼ばれます。
  • ファクトを共通の次元レベルでクエリし、要約したら、中間結果セットをマージできます。SQL用語で言えば、完全外部結合が必要です。
YuichiYuichi

スパース性(sparsity)の不足

不必要なデータがファクトテーブルに存在してしまうことによって、分析の精度や使いやすさが損なわれるという問題を指しています。


🔍 スパース性とは?

データウェアハウス設計における「スパース性」とは、必要なときにだけ行(レコード)を持つという性質です。逆に言えば、「不要なときはレコードを持たない」ことが重要です。

  • 「スパース(sparse)」= まばらな、必要な部分だけが埋まっている状態
  • 「密な(dense)」= すべての組み合わせにレコードがある状態(非効率)

💥 スパース性の欠如による問題

✏️ ケース:注文と出荷を1つのファクトテーブルに混在させた場合

例えば:

customer_id product_id order_date quantity_ordered quantity_shipped
100 333 2024-01-01 5 0

上記のようなレコードは「注文はあったが、出荷はなかった」ことを表します。しかし、ユーザーが 「出荷データだけを分析したい」 と思ってレポートを見た場合、このようなレコードが含まれていると非常に混乱します。

  • ユーザー:「なんで quantity_shipped が 0 のレコードがあるの?キャンセル?トラブル?」
  • 開発者:「それは '注文があったけど出荷がなかった' という事実を記録するために……(略)」
  • ユーザー:「いや、出荷だけ見せてよ!」

📉 問題点:

  • クエリが複雑になる(HAVING 条件や NULL チェックが常に必要)
  • 分析結果が誤解されやすくなる(例:ゼロを欠損と解釈する)
  • BIツールでの可視化にも悪影響(不要なバー、空行など)

✅ 解決策:スパース性を保つスキーマ設計

  1. プロセスごとにファクトテーブルを分離する
    • order_facts:注文データだけ
    • shipment_facts:出荷データだけ
  2. 不要な行を生成しない設計をする
    • 注文だけあった日には shipment_facts にレコードを作らない
  3. 比較が必要な場合は Drill Across を使う
    • 必要なときにだけ結合し、分析目的に応じて柔軟に対応できる

🔁 NULL vs 0 の話

「NULL にしても意味ない。結局出てくる。」

これはその通りです。

  • NULL にしても、レコード自体が存在していれば レポートに登場します。
  • 表示上 0 でも NULL でも、**「そこに何かある」**という事実がレポートに現れてしまう。
  • 本来は「出荷されていないのだから、その行自体が存在しないべき」というのが理想です(=スパース性の維持)。

📌 まとめ

概念 内容
スパース性の欠如 本来存在しなくてよい行まで記録されてしまうこと
問題 不要なデータが混ざることで、分析の精度・使いやすさが下がる
解決策 プロセスごとのファクトテーブル設計+Drill Acrossでの比較
NULL vs 0 レコードがある限り表示されるため、NULLでも回避不能
YuichiYuichi

Conformed Dimensionsとは、

複数のファクトテーブル間で共通して使えるディメンションのこと。これにより、異なるビジネスプロセスを横断して一貫した分析(=ドリルアクロス)が可能になります。


**Types of Dimensional Conformance(ディメンション整合のタイプ)**について


✅ 1. Shared Dimensions(共有ディメンション)

  • 同一のディメンションテーブルを複数のファクトテーブルで使うケース。
  • 最も明確な整合の形。
  • 例:date_dimproduct_dim を売上・在庫など複数の事実テーブルで共有。

✅ 2. Conformed Rollups(整合ロールアップ)

  • 異なる粒度のディメンションだが、上位レベルで整合性が取れている状態。
  • 例:store_dim(店舗)と region_dim(地域)は構造が異なるが、共通の地域コードで結合できる。

✅ 3. Degenerate Dimensions(縮退ディメンション)

  • ファクトテーブル内に直接格納されたディメンション(例:注文番号など)も、他のプロセスと共通で使える場合は整合していると見なせる。

✅ 4. Overlapping Dimensions(重複ディメンション)※議論あり

  • 異なるディメンションテーブルだが、一部の値や意味が重複しているケース。
  • 例:customer_dim_onlinecustomer_dim_store に一部同じ顧客が存在する場合。
  • 整合と認めるかどうかは設計者や組織の判断に依存
YuichiYuichi

適合マトリクス(conformance matrix)

適合マトリクスは実装の青写真として機能します。
https://blog.chrisadamson.com/2012/06/conformance-matrix.html

マトリックス図を使用して、ファクト テーブルまたはサブジェクト領域全体のディメンションの適合性を文書化

適合バス(Conformance Bus)

ディメンションモデルにおける適合フレームワーク(conformance framework)は、ディメンション・データウェアハウス設計における最上位レベルの重要項目です。
KimballとRossはこの適合フレームワークを「適合バス(Conformance Bus)」と呼んでいます。

適合バスは、

  • 各サブジェクトエリア(業務領域)の個別ニーズに対応しながら
  • 領域間の比較や統合的な分析も可能にします。

その結果、エンタープライズ全体を対象とした分析基盤を実現し、**ミクロレベル(個別プロセス)マクロレベル(全体プロセス)**の両方で比較・分析を行えるようになります。

適合ディメンションは設計の中心的な機能
ディメンション設計と適合性フレームワークが完成したら、実装プロジェクトを本格的に開始できます。

YuichiYuichi

https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/books/
入門には『Data Warehouse Lifecycle Toolkit』、モデリングには『Data Warehouse Toolkit』、ETLには『ETL Toolkit』、Microsoft向けには『Microsoft Toolkit』、記事集には『Kimball Group Reader』がおすすめです。

✅ Kimball Groupの代表的な書籍まとめ

書籍タイトル 主な内容・特徴
The Data Warehouse Toolkit, Third Edition (Kimball and Ross) ディメンショナルモデリングの決定版ガイド。スタースキーマ設計を中心に、モデルパターンを体系的に解説。
The Data Warehouse Lifecycle Toolkit, Second Edition (Kimball, Ross, Thornthwaite, Mundy and Becker) データウェアハウスプロジェクト全体の進め方(要件定義→設計→開発→運用)を網羅した実践ガイド。
The Kimball Group Reader, Second Edition – Remastered Collection (Kimball and Ross) Kimball Groupが発表した記事、デザインTips、ホワイトペーパーを再編集したベストセレクション。
The Microsoft Data Warehouse Toolkit, Second Edition (Mundy and Thornthwaite) SQL Server 2008 R2とMicrosoft BIツールを使って、Kimball方式でDWHを構築するためのガイド。
The Data Warehouse ETL Toolkit (Kimball and Caserta) ETLプロセスにフォーカス。データ抽出・クレンジング・整合・配信に関する技術を体系的に紹介。
Kimball's Toolkit Classics 「Data Warehouse Toolkit(第2版)」「Lifecycle Toolkit(第2版)」「ETL Toolkit」をセットにしたクラシックコレクション。
The Microsoft Data Warehouse Toolkit (Mundy and Thornthwaite) SQL Server 2005版。Microsoft製品によるDWH構築方法を解説。(※こちらは少し古め)

✅ 選び方ガイド

  • 📘 モデリングを極めたい → 「The Data Warehouse Toolkit」
  • 📗 プロジェクト全体の流れを学びたい → 「The Data Warehouse Lifecycle Toolkit」
  • 📙 ETL設計に特化したノウハウが欲しい → 「The Data Warehouse ETL Toolkit」
  • 📕 Microsoft環境(SQL Server)でやりたい → 「The Microsoft Data Warehouse Toolkit」
  • 📓 短時間でKimballのエッセンスを広く知りたい → 「The Kimball Group Reader」
YuichiYuichi

https://chrisadamson.com/star-schema-complete-reference

Star Schema: The Complete Reference

スタースキーマ、スノーフレーク、キューブを扱うすべての方のために書かれた、次元モデリングの包括的なガイドです。その広範かつ奥深い解説は、初心者から上級者まで、あらゆる方にとって最適なリファレンスとなっています。

Data Warehouse Design Solutions

スタースキーマ設計の原則を徹底的に解説しています。

Mastering Data Warehouse Aggregates

スター スキーマ データ ウェアハウスのパフォーマンスを向上させる最も効果的なツールであるディメンション集計について詳細に説明した初めての書籍です。

ログインするとコメントできます