DB Stories

DBに関する過去、現在、未来の話題をプロフェッショナルの視点で紹介

ファクトテーブル(4)

異なる粒度を持つファクトテーブル

複数のファクトが異なる粒度を持つ場合、これらは異なるプロセスであると言えます。一つのファクトテーブルに異なるタイミングで発生するイベントを保持する場合、それぞれのプロセスを分析する場合を妨げます。この時、別々のファクトテーブルに保持させることでより容易に分析することを可能にします。

具体的に理解するために、受注と出荷を例にしてみます。セールス部門における業務要件は以下の通りです。

  • 受注量(quantity ordered)を「日付」「顧客」「商品」で分析する。
  • 出荷量(quantity shipped)を「日付」「顧客」「商品」「配送業者(shipper)」で分析する。

この業務要件は前回紹介した例と異なり、受注量と出荷量の分析軸は同一でなく、出荷量にのみ「配送業者」という分析軸が存在しています。

一つのファクトテーブルがもたらす混乱

次の図は販売についてのスタースキーマを示しています。このファクトは受注量(quantity ordered)と出荷量(quantity shipped)を保持しています。

f:id:good-value:20171007152655j:plain

このファクトテーブルは受注、出荷、もしくはその二つのセットで「日付」「商品」「顧客」、出荷についてのみ「配送業者」という粒度を持っています。これまでの説明で見てきたように、「もしくは(or)」という表現は問題が生じる兆候といえます。今回もまた別の混乱が存在しています。

前回紹介したスタースキーマと「配送業者(shipper)」ディメンションが存在している点で異なっています。ある日にある商品をある顧客から受注して、出荷が行われていない場合、この設計においては特別な行を配送業者ディメンションに追加する必要があります。この行は図に色を付けている、サロゲートキー0となっている行です。そしてこのファクトテーブルの先頭3行に受注が行われたが出荷が行われていない状況を示すこのキー(0)をもつ行が存在しています。

この受注と出荷という複数のプロセスを一つのファクトテーブルで扱う場合における1つのプロセスの分析を「出荷」を例にして見ていきます。

f:id:good-value:20171007152721p:plain

この図は顧客(customer)777における商品(product)と配送業者(shipper)別の出荷量(quantity shipped)を示します。ユーザーは主キーごとの値ではなく、ナチュラルキー(ユーザーの認識している商品コード)や商品名ごとに分析を行う必要があります。

前回の例を見てきたように、この帳票は0の値を持つ行によって混乱を生むことになります。さらに、配送業者なし(not a shipper)という直感で理解が難しい3行が含まれています。この3行の存在は、他の出荷されていない商品(注文がないため)が表示されていないことからという意味でユーザーは混乱します。この状況は前回紹介したものと同じテクニックで扱うことができます。つまり、HAVING句の利用とファクト種別を持つ列を持たせることです。しかしこの対策をとることで生じる問題点は前回紹介と同じものとなります。(つまり、「ゆでガエル」であり著しく保守性が悪くなります)

[NOTE] 今回の例において注文と出荷が同一商品、同一日に行われた場合さらに混乱を生むことになります。この場合、ファクトには2行登録を行います。一行目は受注データで出荷に関するデータは未設定、もう二行目は出荷データで受注に関するデータが未設定なものです。どのような状況においてもこの設計では注文と出荷が同じ行で扱われることはないということです。

一つのファクトテーブルを利用せる設計でもう一つの方法として配送業者が設定されていないことを示すNULL値を許容するものがあります。この方法もさらなる混乱を生じさせることになります。

f:id:good-value:20171007152746p:plain

このNULL値の利用は次の図のように配送レポート(shipper report)から余計な行を消すことができます。先ほどの例(not a shipperとせざるを得なかった)と違って出荷業者(shipper)ディメンションの値が設定できるためです。しかしながら2つ目の帳票にあるように、配送業者が分析軸に含まれない場合、ファクトからは0が返されます。これは配送業者ディメンションテーブルとファクトが結合されていないことから発生します。

[TIP] 繰り返しますが、複数のファクトテーブルが異なる粒度を持つ場、これらは異なるプロセスであることになります。これらを一つのファクトテーブルで扱う場合、それぞれのプロセスで分析する場合に混乱の元となります。

ファクトテーブルにおける出荷業者(shipper_key)にNULL値を設定を行ったとき、注文と出荷を同時に分析する場合にそれぞれ別の結合を実施する必要があります。この場合、注文に関するデータはすべてのファクトが必要となるため外部結合の優先テーブルとなります。この外部結合においては、配送業者ディメンションの値(例えば、shipper type)で分析するのは困難です。

一つのファクトテーブルを利用する場合、ディメンションと選択的なリレーション(optional relationship)を作成するという方法もあります。例えば、受注ごとに 「リレーションを切り替える管理的な項目」を持たせる方法です。この管理項目はファクト粒度に依存しないことになります。この選択的なリレーション(optional relationship)については後程紹介することにします。

(続く) 次回は「個別にファクトテーブルを保持する設計とした場合」についてです。