數據倉庫設計與數據建模指南

數據倉庫及為何要建模

拋開教科書式的定義來說,數據倉庫(開源的 Hadoop 體系和阿裡的 MaxCompute/ODPS 等)本質上也是數據庫,隻不過它主要用於:

1.從外部數據源引入和存儲歷史數據;

2.分析數據。

因此相比事務性數據,數據倉庫對數據集成和數據分析能力要求較高,相對應的功能更豐富和更強大。比如對復雜的 JSON 文本處理和分析, 可以通過集成 Java / Python/Shell 等語言自定義函數來實現更加靈活的處理。

什麼時候我們需要開始使用數據倉庫呢?

  • 需要分析的數據量較大(單批 GiB),此時事務性數據庫分析性能堪憂,需要通過建立索引而且會分析查詢會影響在線事務。而數倉一般采用列式存儲,自帶索引性能加成。
  • 分析查詢不想影響在線事務
  • 需要記錄歷史數據
  • 需要對來自不同數據庫、數據源的數據進行整合、關聯分析和交叉探查。比如將存儲在 SLS 的用戶日志和 MySQL 的用戶信息進行關聯分析,通過用戶的行為日志建立用戶畫像。
  • 批處理分析,需要定期批量查詢分析數據並生成結果,比如各種 BI 報表。
  • ……

數據倉庫系統一般采取下圖架構來滿足上述使用場景的:

  • 數據從不同的數據源引入到統一的存儲
  • 在統一存儲裡進行分析計算
  • 計算得到分析結果給外部消費
  • 串聯上述數據引入、處理和分析過程的程序就是 ETL(Extract-Transform-Load,抽取-轉換-加載)任務

如程序語言設計大師 Niklaus Wirth 所說,程序=算法+數據結構。數據倉庫這一大程序中關註最重要的2件事情就是:

  • 數據倉庫的數據結構:如何設計數據的存儲格式和數據之間的關聯關系?也就是數據建模。
  • 數據倉庫的算法:如何編寫和調度數據處理任務,完成數據的引入、處理分析算法。也就是ETL任務。

其中本文將主要著墨於第一件事:數據建模——如何組織數據倉庫的數據和數據之間的關系。

數據模型簡史

數據模型,也就是數據的組織形式。數據模型的發展也是數據庫的發展史,不同的數據庫適應不同的數據模型,例如關系模型對應現在關系數據庫,圖模型對應瞭圖數據庫等。

第一代:層次模型 VS 網絡模型

層次模型簡單來說是樹狀模型,從根節點的數據往下拆分子節點的子數據。1960 年代第一代數據庫誕生的時候,還隻是把文件訪問封裝起來,訪問數據庫就是類似於訪問一系列文件目錄裡的文件。

因此常見的數據訪問模式是根據某一個父節點的值檢索子節點的全部或者部分值,例如下圖,查詢信息學院計算機系教師張麗的情況, 數據的訪問就需要從系 -> 教研室 -> 教師這樣的路徑進行。但是缺點很明顯:隻能表達 「1對多」 的關系,不能表達「多對多」的關系。

網絡模型是對層次模型的延伸,允許單個節點存在多於一個父節點,實現數據之間「多對多」的關系。數據的訪問通過各種鏈表遍歷進行訪問,用戶需要自己編寫查詢過程。

總而言之,這個時期的數據庫就是玩各種數據結構, 指針、鏈表,這是因為當時硬件的運算和存儲能力還比較弱且昂貴,半導體集成電路剛剛產業化,這種為瞭性能而犧牲查詢體驗的‘削足適履’式玩法被廣泛接受,這也符合當時的歷史環境。

第二代:關系模型

計算機相關專業出身的同學可能對關系數據模型更加比較熟悉,因為這是數據庫科目考試重點啊。

關系模型由時任 IBM 研究員 Edgar Codd 於 1970 年在論文 A Relational Model of Data for Large Shared Data Banks 中提出,而當時還是層次模型和網狀模型的數據庫產品在市場上占主要位置,這篇論文發表以後關系型數據庫開始吊打舊模型,關系數據模型和關系數據庫成為主流,一直延續至今。( Codd 憑借對關系數據庫領域的貢獻獲得圖靈獎,但據說當時這篇論文因過於出眾差點被拒掉)

它能脫穎而出是因為對數據訪問做瞭很好的抽象,有關系代數作為堅實理論基礎。用戶隻需要用 SQL 聲明要的結果,數據庫的事務執行器和查詢優化器會幫你從數據庫裡正確地插入和撈出數據,這個方法將數據的查詢和具體的查詢過程分開,用戶不需要去玩指針遍歷各種數據結構,大大提高程序員的搬磚效率因而得到市場用戶的擁護。

在關系模型的世界裡,數據被分為「實體」和「關系」。如下圖,矩形的「學生、課程、教師」作為「實體」,「選課和教課」作為「關系」將「學生、課程、教師」關聯起來。

但此時的數據庫主要的應用場合是各種業務系統,需要滿足各種交易事務處理的場景,這類應用也被稱為 OLTP(online transaction processing)。在這個場景下,為瞭數據一致性和減少數據冗餘,設計的表格需要滿足3NF范式約束。

第三代:3NF關系模型 vs 維度模型

這個階段也可以看成是關系數據庫的一個自然延伸。隨著數據庫技術的普及應用,越來越多的數據被存儲在數據庫中,除瞭支持業務的事務處理以外, 如何讓這些數據發揮更大的作用,則是一個亟待解決的問題。

  • 從業務層面來看,業界發現需要為企業構建一個用於分析業務和幫助業務決策的數據集合——數據倉庫
  • 從技術層面來看,需求推動創新,針對分析的數據庫產品逐漸被開發,這類產品應用也稱為 OLAP(online analytical processing) 產品。

數據倉庫屬於 OLAP 應用,主要用於執行分析任務,使用場景和 OLTP 不太一樣,相比 OLTP 事務數據庫有自己的一些特點,比如「一次性寫入、多次讀取、幾乎不修改」。例如賬單數據,一旦發生就成為歷史的記錄, 很少發生事後修改。盡管 OLTP 關系數據庫也能實現上述要求, 但是要讓復雜分析任務高效地執行,則需要針對 OLAP 應用設計對應的數據模型。

這些數據倉庫的數據建模理論逐漸分為自上而下的 Inmon 派和自下而上的 Kimball 派

  • Inmon 的自上而下是指先從上遊業務系統的數據著手,進而構建出整個企業共享的數據倉庫(Enterprise Data Warehouse),在這個數據倉庫下在延伸出不同主題的數據集市(Data Marts,數據集市就是關於某一主題的小數據倉庫),比如賬單數據作為一個賬單數據集市。

【Inmon 數據架構】

  • Kimball 的自下而上是指從最下遊的業務數據分析需求開始,先想清楚要解決什麼問題,解決這些問題需要知道哪些業務過程、所要分析的數據的維度和指標度量需求,再去上遊撈取需要的數據。根據分析問題的領域不同,就逐漸積累出瞭一堆數據集市,Kimball 認為這堆逐漸構建出來的數據集市就是邏輯上的數據倉庫瞭。

【Kimball 數據架構】

由於兩派構建數據倉庫的根本理念上就存在著差異,所以他們的數據建模方法也不同。

  • Inmon 偏向於構建一個企業級別中央大一統的數據倉庫,所以 Inmon 推崇使用 ER 模型建立關系建模並堅持使用 3NF 規范化進行數據模型的建設,這樣的好處又很多:數據一致性好,一處改動多處一致、減少數據冗餘等等。這種方式對業務穩定的企業來說是可行的,但這樣設計和開發效率較低,不夠敏捷,不適合業務發展迅猛的企業,尤其是互聯網行業;
  • Kimball 建議不要一上來就想搞大工程,要以需要分析的問題和業務為導向,小步快跑地集成數據來解決一個個具體的業務問題,並逐漸積累為數據倉庫,這種小步快跑的迭代方法更敏捷,更受互聯網公司青睞。它以分析問題為導向,因此重點關註業務問題分析中需要什麼「維度屬性」以及「事實度量值」,比如分析銷售額時會重點關註城市、日期、商品類別等維度,以及銷售額、成本、利潤等事實度量值。因此 KimBall 提出的「維度建模」方法以構建「維度表」和「事實表」為核心,並且為瞭讓分析師更高效使用數據表,減少表之間的 Join 關聯操作,因而放棄3NF規劃化,提倡反規范化,構建大量寬表。當然缺點就是數據大量冗餘、數據不一致,而且容易重復建設。

說瞭那麼多,其實核心觀點就是:不同的應用類型(OLTP/OLAP)和不同的企業業務類型就應該用不同的數據建模方法。

在互聯網行業中,需求變化飛快,追求敏捷更符合實際場景,阿裡的 MaxCompute 也推薦使用維度建模,除此以外,微軟的 Power BI、Tableau 等業界 BI 數據工具都可以采用維度建模,本文主要介紹的也是 Kimball 的維度建模理論。

接下來,本文將分為2部分進行介紹:1. 微觀設計部分:主要介紹維度建模方法。如何根據具體的業務進行維度表和事實表的表結構設計,主要讓數倉滿足業務的功能性需求。2.宏觀設計部分:主要介紹數據分層。如何組織表之間的層次關系,主要讓數倉保障一致性、節省存儲、提高數據復用性等非功能需求。

微觀設計:維度模型建模

本部分我們主要關註如何根據業務需求來構建數據倉庫裡的表結構,重點構建2種表:事實表和維度表。

維度世界觀:維度+事實

維度建模方法和關系建模方法的根本區別來自他們組織數據的視角和使用數據的目的不同。

關系建模將世界看作「實體」和「關系」,通過這兩個概念和3NF規劃化對業務進行建模,最後結構化為表格。這種視角源於對數據一致性、減少數據冗餘的追求。如下示例,是一個簡單的零售系統的關系建模示意圖。

【關系建模】

而維度建模則將世界看作「維度」和「事實」,或者稱為「維度」和「度量」。

  • 維度是用來描述屬性和篩選數據的,比如商品的類別、產地
  • 事實表示某個業務的度量、指標或者數字,比如商品的銷售量和庫存。

將維度和事實各自整理為表格的每一列,表格的每一行則代表一個度量事實。提供給下遊分析消費。這種視角源於對數據分析需求便利性的追求。

【維度建模】

上方2圖同樣是對零售訂單的進行建模,讀者可以對比一下兩種方式之不同。

  • 技術上,關系建模主要構建實體表和關系關聯表。維度建模主要構建「事實表」和「維度表」,並且以事實表為中心,關聯所有維度表——因此這種建模方法也被稱為星型模型(Star schema)。
  • 目標上,兩種建模方法的內核目標不同。維度建模以分析的便利性和查詢性能為主要目標,分析查詢主要是篩選+聚合數據兩個操作,因此在事實表就已經將數據分為【維度】和【度量】兩部分,維度用於篩選,度量用於求和等聚合計算。並且為瞭提高查詢性能,需要減少不同表關聯 Join 操作,因此將常用的維度從維度表裡冗餘到瞭事實表中(這個冗餘操作在維度建模裡叫做維度退化),不常用的維度會獨立保留在對應的維度表裡。

比如要對比分析18歲和25歲女性客戶在上月的購物情況。

如果在關系建模下進行類似的查詢,查詢邏輯不僅冗長,而且需要好多個關聯操作,這種查詢性能難以接受,這在上世紀後期大型傳統零售企業的日百萬級訂單量都很難頂得住,何況在當前電商公司更巨大的日訂單量。

SELECT
b.訂單日期 - c.出生年月 AS 客戶年齡
,SUM(a.商品數量 * d.商品單價)
FROM 訂單-商品關系表 a
LEFT JOIN 訂單實體表 b
ON a.訂單ID = b.訂單ID
LEFT JOIN 客戶實體表 c
ON b.客戶ID = c.客戶ID
LEFT JOIN 商品實體表 d
ON a.商品ID = d.商品ID

WHERE b.訂單日期=上個月
AND b.訂單日期 - c.出生年月 IN (18, 25)
AND c.性別=‘女性’
GROUP BY
客戶年齡

赞(0)