Sql-Server-2008

數據倉庫 - 維度、事實或退化維度

  • April 21, 2015

我正在為一個計費系統建構一個倉庫,該系統在同一張發票上對許多服務/公用事業進行計費,因此我在符合公認的倉庫設計方法時遇到了真正的麻煩。我想我仍然非常戴著 OLTP 帽子。

例如,可以生成一張包含電費、燃氣費和行動電話費的發票。

賬單的所有三個組成部分,本身有兩個組成部分,固定費用和基於使用的費用。即使簡化為只是一部手機,它仍然意味著儲存業務所需的詳細程度我需要 2 個事實表:

FactMobileFixedCharge
FactMobileCalls

這些中的每一個都進入一張發票,除此之外還有發票級別的交易,所以我現在需要一個進一步的事實表:

FactInvoiceTransaction

這個簡單範例的基本架構如下:

在此處輸入圖像描述

我所做的所有閱讀都接近InvoiceLineItem範例以解決發票看起來像事實和維度的問題,其中發票的事實基本上被傳播到子表,導致一些冗餘但符合標準實踐。

在生產計費系統本身中,有 15 個表包含出現在發票上的項目、一個包含發票級別費用的匯總表和按類別分類的其他 15 個表中的費用匯總表,以及發票表本身。

不過,我覺得我的情況與此不符,因為發票有許多不同的東西也需要報告(發票地址、發票上的行銷材料、付款方式、發票格式、電子郵件、線上或紙質賬單,結轉餘額、自上次發票後的付款等)。雖然如果我有一個或兩個表,這是可以接受的冗餘,但對於 15 個事實表來說似乎很多。

除了在有多個表時有很多冗餘之外,我還需要連結FactMobileCallFactMobileCharge獲取同一張發票的記錄,而且我不相信退化維度是連結兩者的好方法。

基本上,這一切都指向Invoice一個維度,尤其是在發票級別沒有測量值的情況下,但仍然感覺這應該是一個事實,因為每次導入只會有新記錄。

這導致了我的問題:

  1. 我認為在這種情況下應將發票視為事實是否正確?
  2. 如果是這樣,是否可以接受更多事實來引用這一事實,或者是否有更好的方法來解決這個問題?
  3. 我不敢相信我是唯一遇到InvoiceLineItem範例似乎不適合的情況的人。有沒有公認的方法來處理這個問題?

有關更多資訊,我的倉庫模式目前看起來像這樣(我已經承認 Invoice 是一個類似於維度的事實):

在此處輸入圖像描述

這就是我自己處理它的方式。請記住將您的 Facts 視為“動作”或“動詞”,將您的維度視為您的事實的描述符。

因此,您的發票和發票行項目都是事實。處理此問題的一種方法是您提到的,將事實表製作為發票級別行項目的粒度。這將導致您提到的某些事情的冗餘。如果對帳單地址維度和某些發票級別的事實(例如稅)沒有問題,甚至可以將其分解為行級別項目,然後可以匯總回發票級別的金額。

如果您的發票級別事實不能很好地分解,這種方法可能會失敗。例如,是否允許客戶使用多種付款方式?發票上是否附有不止一種類型的行銷材料?行銷材料是否與特定行項目相關?

提出這些問題肯定會導致您創建多個事實,例如 FactInvoiceLineItem、FactInvoice、FactPayments 等,您最終會將這些事實與發票編號等資訊聯繫在一起。這樣做將使您更靈活地更好地分析特定事實。

如果採用這種方法並且您正在從事實表建構多維數據集,我建議使用視圖來載入您的多維數據集。通過這種方式,您可以對發票有一個高級視圖,該發票加入了您的各種事實表,並在其中進行了度量,例如行項目數、付款次數等。

綜上所述,我相信走這條路比拆分具有相同粒度的事實表要好得多。

如果您需要更多幫助來解決問題,請隨時回復更多詳細資訊。

一個兩層的事實表通常比它的價值更麻煩。這是你 OLTP 正常化的本能 - 與之抗爭!我花了幾個月的時間來理解倉庫/星型模式範式。

所有這些發票標題資訊都可以放入幾個額外的維度中。這只會在INT您的事實表中添加幾列,因此所需的額外空間 - 它很重要 - 是最小的。這些維度表將只包含不同的數據集,因此實際上幾乎沒有冗餘。

根據您的描述,我將從以下內容開始:

Invoices

  • InvoiceSK(合成密鑰,非集群 PK)
  • 固定收費(事實)
  • 用法(事實)
  • UsageCharge(事實)
  • InvoiceNumber(退化維度)
  • AccountSK(合成密鑰,FK to Accounts
  • MarketingMaterialSK(合成密鑰,FK to MarketingMaterial
  • ProductSK(合成密鑰,FK to Products
  • DateBilledSK(合成密鑰,FK to Dates
  • DatePaidSK(合成密鑰,FK to Dates

Payments

  • PaymentSK(合成密鑰,非集群PK)
  • 支付金額(事實)
  • AccountSK(合成密鑰,FK to Accounts
  • PaymentMethodSK(合成密鑰,FK to PaymentMethods
  • DatePaidSK(合成密鑰,FK to Dates

Accounts 這將是類型 2 SCD,因此為每個事實記錄儲存的資訊(例如,地址)反映了當時文件上的資訊。

  • 帳號
  • 名字,姓氏
  • 街道地址、城市、地區、國家、郵政編碼、區號

Products

  • 產品類別(電、氣、電話)
  • 產品名稱
  • 產品程式碼

我會讓外鍵純粹是合乎邏輯的,而不是強制執行的;只要您的 ETL 很緊,您就不需要成本。

我不知道PaymentMethods您的數據庫中需要什麼。如果只是“他們使用支票、卡/借記卡,還是這是賬單調整?” 你可以把它變成一個退化的維度Payments;如果它有卡號和到期日期等欄位,則應將其設為維度以避免載入事實表。

您可能想要區分BillingAddressServiceAddress。您可以在表中創建兩組地址欄位Accounts,或者將地址配置到一個新表中並讓事實表引用兩者。在其他條件相同的情況下,我傾向於第一個 - 它會使事實表盡可能窄。

棘手的部分在於連接InvoicesPayments. 這是一個多對多的關係,在倉庫中往往會很痛苦。在許多情況下,您不需要:您可以匯總Invoices到某個時間點,並簡單地報告到期餘額(您可以將其儲存在每月快照表中)PaymentsAccountNumber但是,業務使用者可能需要更精確的突破。該表可以非常簡單:

PaymentAllocation

  • 發票S​​K
  • 付款SK
  • 數量
  • { InvoiceSK, PaymentSK } 上的 PK

…但很少決定每筆付款中有多少美元應該用於每個發票行項目。將收入分配給尚未全額支付的最早發票行項目?這是一個開始。

類似的方法適用於將成本分配給收入,反之亦然,以計算細粒度的利潤。這是很多工作,但最終您可以計算出哪些客戶和產品實際上在推動業務 - 這就是黃金。

未來的步驟可能是創建一個Households表來對單個地址的帳戶進行分組。

引用自:https://dba.stackexchange.com/questions/53721