Junk Dimension (ジャンクディメンション) は、トランザクションに付随する多数の低カーディナリティなフラグやコード値を 1 つのディメンションテーブルに束ね、[[ファクトテーブル]]からサロゲートキー 1 本で参照する設計パターンである。束ねる属性は互いに無関係で良い。 この手法は [[ディメンショナルモデリング]] の設計テクニックの 1 つで、[[Ralph Kimball]] が定式化した。フラグごとにディメンションを切り出すと FK が増えて [[Centipede Fact Table]] に陥るが、束ねれば雑多なフラグを追い出しつつ、絞り込みや集計の置き場所を確保できる。 > [!info] > 原典は『[[The Data Warehouse Toolkit]]』(3rd Edition) 6 章 "Order Management"。Kimball Group の [Junk Dimensions](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/junk-dimension/) テクニックとしても解説されている。 > [!note] > 「ジャンク」はキッチンの「がらくた引き出し」になぞらえた呼び名である。輪ゴムやクリップのように、専用の収納を用意するほどではない小物をまとめて放り込む引き出しに、低カーディナリティ属性の置き場所を重ねている。 ## 構造 Junk Dimension は他のディメンションと同じく、サロゲートキーを主キーに持ち、ファクトテーブルから FK で参照される。 他のディメンションとの決定的な違いは、互いに関連の薄い複数の低カーディナリティ属性を 1 つのテーブルに同居させることにある。属性の組み合わせ自体が各行を識別するため、業務上の自然キーは持たない。 以降は EC サイトの注文トランザクションを例に、支払区分 (2 種類)・注文チャネル (3 種類)・注文タイプ (3 種類) を `dim_order_profile` にまとめ、`fct_order` は `order_profile_key` 1 本で参照するものとして解説する。 ```mermaid erDiagram dim_date ||--|{ fct_order : "date_key" dim_customer ||--|{ fct_order : "customer_key" fct_order }|--|| dim_product : "product_key" fct_order }|--|| dim_order_profile : "order_profile_key" fct_order { order_key int64 "[SK]" date_key int64 "[FK]" customer_key int64 "[FK]" product_key int64 "[FK]" order_profile_key int64 "[FK]" order_id string "[GD, DD]" order_amount int64 "[FA]" } dim_order_profile { order_profile_key int64 "[SK]" payment_type string "[GD]" order_channel string "[GD]" order_type string "[GD]" } ``` ## 作り方 Junk Dimension を用意する方法は 2 つある。どちらが優れているという固定の答えはなく、組み合わせ数と、参照整合性や全組み合わせの保持が必要かに応じて選ぶと良い。列指向 DB では両者の行数の差が性能にほぼ響かないため、純粋に設計判断になる。 > [!info] > 出現の組み合わせは Kimball (『[[The Data Warehouse Toolkit]]』)、直積は Adamson (『[[Star Schema The Complete Reference]]』) が示す方法である。 ### 1. ファクトテーブルに出現した組み合わせから作る ファクトの元データに実際に現れた属性の組み合わせだけを行にする。出現する組み合わせは理論上の総数よりはるかに少なく、多くてもファクトの行数で頭打ちになる。組み合わせ数が膨大、または実際に現れるのがその一部だけのときに向いている。 支払区分 (2) × 注文チャネル (3) × 注文タイプ (3) = 18 通りのうち、実際には次の 10 通りだけが現れたとする。残りの組み合わせは行を持たない。 | order_profile_key (SK) | payment_type (PK) | order_channel (PK) | order_type (PK) | | ---------------------- | ----------------- | ------------------ | --------------- | | 1 | Cash | Web | New | | 2 | Credit | Web | Reorder | | 3 | Credit | Store | Subscription | | 4 | Cash | Phone | New | | 5 | Credit | Web | New | | 6 | Cash | Web | Reorder | | 7 | Credit | Phone | New | | 8 | Cash | Store | New | | 9 | Credit | Store | Reorder | | 10 | Credit | Web | Subscription | ### 2. 全組み合わせを直積で作る ありうる全組み合わせを直積 (cross join) で先に作る。全行が先に揃うため、ファクトのどの行も必ずマッチする行を見つけられ、出現しなかった組み合わせも 0 件として集計に残せる。組み合わせ数が小さく固定的なときに向く。 同じ 3 属性なら、出現の有無に関わらず 2 × 3 × 3 = 18 行すべてを持つ。手法 1 では現れなかった 8 通りも行として残る。属性の数や値が増えると行数は直積で急に膨れ上がり、業務上ありえない組み合わせまで含みうる点には注意する。 | order_profile_key (SK) | payment_type (PK) | order_channel (PK) | order_type (PK) | | ---------------------- | ----------------- | ------------------ | --------------- | | 1 | Cash | Web | New | | 2 | Cash | Web | Reorder | | 3 | Cash | Web | Subscription | | 4 | Cash | Store | New | | 5 | Cash | Store | Reorder | | 6 | Cash | Store | Subscription | | 7 | Cash | Phone | New | | 8 | Cash | Phone | Reorder | | 9 | Cash | Phone | Subscription | | 10 | Credit | Web | New | | 11 | Credit | Web | Reorder | | 12 | Credit | Web | Subscription | | 13 | Credit | Store | New | | 14 | Credit | Store | Reorder | | 15 | Credit | Store | Subscription | | 16 | Credit | Phone | New | | 17 | Credit | Phone | Reorder | | 18 | Credit | Phone | Subscription | ## 命名規約 Junk Dimension は概念的に親ファクトテーブルに付随するディメンションであり、独立したビジネスエンティティではない。 命名は `dim_{{ FACT_ENTITY }}_{{ ROLE }}` の形に揃えると、テーブル名から所属するファクトテーブルと役割が両方読み取れる。 この `{{ ROLE }}` はディメンションの性質に応じて選び、profile (transaction profile dimension) や indicator (indicator dimension) などを当てる。 - ✅ 推奨: `dim_order_profile` / `dim_order_indicator` (親ファクトテーブルと役割の両方が読み取れる) - ❌ 非推奨: `dim_profile` (役割しか分からず、親ファクトテーブルが分からない) - ❌ 非推奨: `dim_order` (注文ディメンション全体と読めてしまい、役割が分からない) > [!warning] > テーブルの物理名にもビジネスユーザーとの会話にも「junk (ジャンク)」という表現は使用してはならない。「junk」は、物理名では内容を表さず、ビジネスの場ではデータの価値が低い印象を与えるためである。 ## 関連ノート - **[深掘り]** [[長文テキスト属性は Text Comment Dimension に切り出す]]: Junk Dimension に入れてよい属性の境界 (高カーディナリティな長文テキストは含めない) を具体例で深掘りする