ひとことで言うと#
DWH(データウェアハウス)を**「ファクト(事実)」と「ディメンション(切り口)」の2種類のテーブル**で設計する手法。分析者が直感的にクエリを書ける構造を作ることで、「こういう切り口で見たい」という要望に素早く応えられるようになる。
押さえておきたい用語#
- ファクトテーブル(Fact Table)
- ビジネスで発生した数値データ(売上額、数量、クリック数など)を記録するテーブルのこと。1行が1つのイベント・トランザクションに対応する。
- ディメンションテーブル(Dimension Table)
- ファクトを分析する切り口の属性を格納するテーブルを指す。日付・顧客・商品・店舗・地域などが代表例。
- スタースキーマ(Star Schema)
- 中央のファクトテーブルを複数のディメンションテーブルが囲む構造で、ER図が星形に見えることからこの名前がついた。最もシンプルなディメンショナルモデル。
- スノーフレークスキーマ(Snowflake Schema)
- ディメンションテーブルをさらに正規化して分割した構造である。雪の結晶のように枝分かれする形状が特徴。
- 粒度(Grain)
- ファクトテーブルの1行が何を表すかの定義。「1注文1行」「1日1店舗1商品カテゴリ1行」など、最初に決めるべき最重要項目。
ディメンショナルモデリングの全体像#
こんな悩みに効く#
- DWHのテーブル設計が業務システムのERモデルそのままで、分析クエリが複雑になりすぎる
- 「商品カテゴリ別×月別×地域別の売上」を出すのに毎回10テーブル以上をJOINしている
- 新しい分析軸を追加するたびにテーブル構造を大幅に変更する必要がある
基本の使い方#
ディメンショナルモデルは1つのビジネスプロセスにつき1つのファクトテーブルを設計する。
ビジネスプロセスの例:
- 販売: 注文・売上のトランザクション
- 在庫: 日次の在庫スナップショット
- Webアクセス: ページビュー・クリック
- 顧客サポート: 問い合わせ・解決
最初に取り組むべきは、最もビジネスインパクトが大きく、データが揃っているプロセス。
ファクトテーブルの1行が何を表すかを厳密に定義する。これがディメンショナルモデリングで最も重要なステップ。
粒度の例:
- 「1注文明細1行」(注文ID × 商品ID)
- 「1日1店舗1商品カテゴリ1行」(集計済みファクト)
- 「1クリック1行」(ログレベルの粒度)
粒度を決めるときのルール:
- できるだけ細かい粒度で始める(後から集計はできるが、細分化はできない)
- 粒度を曖昧にすると二重カウントや欠損の原因になる
- 粒度を文書化し、チームで共有する
ファクトをどの切り口で分析したいかを洗い出し、ディメンションテーブルを設計する。
よく使うディメンション:
| ディメンション | 属性の例 |
|---|---|
| 日付 | 年・月・四半期・曜日・祝日フラグ |
| 商品 | 商品名・カテゴリ・ブランド・単価 |
| 顧客 | 顧客名・セグメント・地域・登録日 |
| 店舗 | 店舗名・都道府県・店舗タイプ |
| プロモーション | キャンペーン名・割引率・期間 |
設計のポイント:
- ディメンションは非正規化する(スタースキーマの場合)
- 属性はできるだけ豊富に持たせる(後から分析の幅が広がる)
- 緩やかに変化する属性(SCD: Slowly Changing Dimension)の処理方針を決める
粒度に基づいて、**外部キー(FK)と数値カラム(メジャー)**を定義する。
ファクトの種類:
- トランザクションファクト: 1イベント1行(売上、クリック等)
- 周期スナップショットファクト: 一定期間の状態を記録(月末在庫、日次残高等)
- 累積スナップショットファクト: プロセスの進捗を追跡(注文→出荷→配達の各日時)
実装時の注意:
- メジャーは加算可能(Additive)かどうかを明記する
- NULLの扱いを統一する(FKのNULLは「不明」ディメンション行を用意)
- サロゲートキー(自動採番の整数)をPK/FKに使う(自然キーはディメンション内に保持)
具体例#
状況: 年商80億円のアパレルEC。基幹システムのERモデルをそのままBigQueryに複製してBIダッシュボードを構築していた。「商品カテゴリ別×都道府県別×月別の売上」を出すのに14テーブルのJOINが必要で、クエリ実行に8分かかっていた。
ディメンショナルモデルの設計:
- ファクト:
fact_order_line(粒度: 1注文明細1行、月間150万行) - ディメンション:
dim_date,dim_product,dim_customer,dim_shipping_address,dim_promotion
導入後の変化:
- 同じ分析がJOIN 4テーブルで完結、クエリ実行時間8分 → 12秒
- 新しい分析軸の追加がディメンションテーブルへの属性追加だけで完了
- アナリストがSQLを書く時間が平均60%短縮
ダッシュボードの更新が高速化したことで、週次レビューで「先週の数字をもっと深掘りしたい」というリクエストにその場で応えられるようになった。
状況: 年間配送件数500万件の物流企業。注文から配達完了までの平均リードタイムが3.2日で、競合の2.1日に劣っている。どの工程がボトルネックかを特定したいが、データが5つのシステムに分散していた。
累積スナップショットファクトを設計:
fact_delivery_pipeline(粒度: 1配送1行)- 各マイルストーンの日時をカラムとして保持:
order_datetime→picking_datetime→packing_datetime→shipping_datetime→delivery_datetime
- ディメンション:
dim_date,dim_warehouse,dim_carrier,dim_destination_area
分析結果:
- 全体の3.2日のうち、倉庫でのピッキング待ちが1.4日を占めていた
- 特定の倉庫(関東第2倉庫)のピッキング待ちが2.1日と突出
関東第2倉庫のレイアウト最適化と人員配置の見直しにより、全体のリードタイムが3.2日 → 2.3日に改善。改善幅0.9日のうち、関東第2倉庫の改善だけで0.7日を占めており、累積ファクトが「どこを直せば全体が動くか」を数字で示した形になった。
状況: 病床数450床の公立病院。電子カルテ・会計システム・予約システムの3つが独立しており、「診療科別×月別×患者属性別の外来患者数」を出すのに担当者が毎月3日間かけてExcelで手作業集計していた。
スタースキーマの設計:
- ファクト:
fact_outpatient_visit(粒度: 1受診1行、月間2.8万行)- メジャー: 待ち時間(分)、診察時間(分)、医療費(点数)
- ディメンション:
dim_date: 年月日・曜日・祝日フラグdim_patient: 年齢層・性別・保険種別・初診/再診dim_department: 診療科・担当医・外来区分dim_time_of_day: 受付時間帯(朝・昼・夕)
月次集計が3日間の手作業からダッシュボードの自動更新に切り替わり、工数は実質ゼロに。さらに「月曜午前の内科外来は待ち時間が平均48分と突出」という発見から予約枠の再配分を実施し、平均待ち時間を35分に短縮できた。
やりがちな失敗パターン#
- 粒度を曖昧にしたまま設計を進める — 「1行が何を表すか」を明確にしないと、二重カウントや集計の不整合が発生する。設計の最初に粒度を1文で定義し、チームで合意する
- 業務システムのERモデルをそのままDWHに持ち込む — 正規化されたERモデルは更新に最適化されているが分析には向かない。ディメンショナルモデルでは意図的に非正規化し、分析のしやすさを優先する
- 最初から完璧なモデルを作ろうとする — すべてのビジネスプロセスを一度にモデリングすると時間がかかりすぎる。最も利用頻度の高い1つのファクトから始め、段階的に拡張する
まとめ#
ディメンショナルモデリングは、DWHをファクト(数値)とディメンション(切り口)の2種類のテーブルで設計する手法。業務システムのERモデルとは異なり、分析者が直感的にクエリを書ける構造を目指す。設計の出発点は粒度の定義であり、これを曖昧にしたまま進めると後から取り返しのつかない問題が生じる。まず1つのビジネスプロセスでスタースキーマを構築し、効果を実感してから拡張していくのが堅実な進め方になる。