1. 程式人生 > 實用技巧 >資料倉庫-維度

資料倉庫-維度

各維度型別

漸變維

描述

漸變維(SCD. Slowly Change Dimension,是一種在多維資料倉庫中實現維度歷史的技術

型別

  • SCD1

通過更新維度記錄直接覆蓋已存在的值,它不維護記錄的歷史

一般用於修改錯誤的資料

  • SCD2

在源資料發生變化時,給維度記錄建立一個新的版本記錄,從而維護維度歷史。

不刪除、修改已存在的資料,新增一條資料

  • SCD3

通常用作保持維度記錄的幾個版本。通過給某個資料單元增加多個列來維護歷史。

例如,為了記錄客戶地址的變化,customer_dim維度表有一個customer_address列和一個previous_customer_address

列,分別記錄當前和上一個版本的地址。

SCD3可以有效維護有限的歷史,而不像SCD2那樣儲存全部歷史。

很少使用,只適用於資料的儲存空間不足並且使用者接受有限維度歷史的情況

維度子集

由來

有些需求不需要最細節的資料。

想要某個月的銷售彙總,而不是某天的資料

相對於全部的銷售資料,只對某些特定狀態的資料更感興趣

事實資料需要關聯到特定的維度,這些特定維度包含在從細節維度選擇的行中,所以叫維度子集。

維度子集比細節維度的資料少,因此更易使用,查詢也更快

描述

子維度是一種一致性維度,由基本維度的列與行的子集構成。

細節維度稱為基本維度,維度子集稱為子維度

基本維度表與子維度表具有相同的屬性或內容,這樣的維度表具有一致性。

一致的維度具有一致的維度關鍵字、屬性列名字、屬性定義以及屬性值。

當構建聚合事實表,或者需要獲取粒度級別較高的資料時,需要用到子維度。

型別

  • 包含屬性子集的子維度

當事實表獲取比基本維度更高粒度級別的度量時,需要上捲到子維度

基本維度和子維度表的主鍵是不同的

比如,日資料上捲到月資料

  • 包含行子集的子維度

基本維度和子維度具有同樣粒度級別的細節資料

基本維度和子維度表的主鍵是相同的

比如,基本維度表中包含多種型別的資料,現在只想根據其中某一型別的資料做統計

  • 檢視維度子集

優點

不真實儲存物理資料,不需要額外的儲存空間

可規避資料不一致的潛在風險

減少資料冗餘

缺點

當基本維度表和子維度表的資料量相差懸殊時,效能會比物理表差很多

如果定義的檢視的查詢很複雜,並且檢視很多的話,可能會對元資料儲存系統造成壓力,嚴重影響查詢效能。

檢視是隻讀的,不能對檢視使用LOADINSERT語句裝載資料

一旦檢視建立,它的結構就是固定的,之後底層表的結構改變,不會反映到檢視的結構中。

角色扮演維度

描述

單個物理維度可以被事實表多次引用,每個引用連線邏輯上存在差異的角色維度

當一個事實表多次引用一個維度表時會用到角色扮演維度。

例如,事實表可以有多個日期,每個日期通過外來鍵引用不同的日期維度,原則上每個外來鍵表示不同的日期維度檢視,這樣引用具有不同的含義。這些不同的維度檢視具有唯一的代理鍵列名,被稱為角色,相關維度被稱為角色扮演維度

層次維度

描述

大多數維度都具有一個或多個層次。如:日期維度就有四級層次:年、季度、月和日。

日期維度是一個單路徑層次,因為除了年-季度--日這條路徑外,它沒有任何其它層次。

舉例

日期維度:年-季度--

地理位置維度:國家---

型別

固定深度的層次
描述

固定深度層次是一種一對多關係

當固定深度層次定義完成後,層次就具有固定的名稱,層次級別作為維度表中的不同屬性出現。

固定層次能夠提供可預測的、快速的查詢效能,可以在固定深度層次上進行分組和鑽取查詢

如:一年中有四個季度,一個季度包含三個月等

查詢型別

l 分組查詢

把度量按照一個維度的一個或多個級別進行分組聚合。

SELECT product_category, year, quarter, month, sum(order_amount) as s_amount FROM sales_order_fact a, product_dim b, date_dim c WHERE a.product_sk = b.product_sk AND a.order_date_sk = c.date_sk GROUP BY product_category, year, quater, month CLUSTER BY product_category, year, quater, month

l 鑽取查詢

把度量按照一個或多個級別進行分組。與分組查詢不同的是,分組查詢只顯示分組後最低級別,即示例中每月的度量彙總值,而鑽取查詢顯示分組後維度每一個級別的度量。

union all

SELECT
product_category, time, order_amount
FROM (
SELECT
product_category,
CASE WHEN sequence = 1 THEN CONCAT('year: ', time)
 WHEN sequence = 2 THEN CONCAT('quarter: ', time)
 ELSE CONCAT('month: ', time) END time,
order_amount, sequence, date
FROM(
SELECT
product_category, MIN(date) date, year time, 1 sequence, SUM(order_amount) order_amount
FROM sales_order_fact a, product_dim b, date_dim c
WHERE a.product_sk = b.product_sk and a.order date_sk = c.date_sk
GROUP BY product_category, year
UNION ALL
SELECT
product_category, MIN(date) date, quarter time, 2 sequence,SUM(order_amount) order_amount
FROM sales_order_fact a, product_dim b, date_dim c
WHERE a.product_sk = b.product_sk and a.order date_sk = c.date_sk
GROUP BY product_category, year, quarter
UNION ALL
SELECT product_category, MIN(date) date, month time, 3 sequence,SUM(order_amount) order_amount
FROM sales order fact a, product dim b,date dim c
WHERE a.product_sk . b.product_sk and a.order date_sk = c.date_sk
GROUP BY product_category, year , quarter , month
) x
CLUSTER BY product_category , date , sequence , time
) y;

使用union all集合操作將年、季度、月三個級別的彙總資料聯合成一個結果集。注意union all的每個 查詢必須包含相同個數和型別的欄位。附加的min(date)sequence匯出列用於對輸出結果排序顯示

grouping__id

SELECT
product_category, time, order_amount
FROM (
SELECT
product_category,
CASE WHEN gid = 3 THEN CONCAT('year: ', year)
 WHEN gid = 7 THEN CONCAT('quarter: ', quarter)
 ELSE CONCAT('month: ', month) END time ,
order_amount, gid, date
FROM(
SELECT
product_category,year,quarter,month,MIN(date) date, SUM(order_amount) order_amount, cast(grouping__id as int) gid
FROM sales_order_fact a, product dim b, date dim c
WHERE a.product_sk = b.product_sk and a.order_date_sk = c.date_sk
GROUP BY product_category, year , quarter,month WITH ROLLUP
) x WHERE gid > 1
CLUSTER BY product_category , date , gid , time
) y;

使用HiveQL提供的grouping__id函式(注意是兩個下劃線)和with rollup子句。rollup會生成按產品型別、年、季度、月及其所有分組的聚合資料行。 with rollupSQL中通用的語法,它只能和group by語句一同使用。rollup子句常被用於計算一個維度中各個層級的聚合資料

select a, b, c, sum(d) from tab1 group by a, b, c with rollup ;
select a, b, c, sum(d) from tab1 group by a, b, c
union all
select a, b, null, sum(d) from tab1 group by a, b, null
union all
select a, null, null, sum(d) from tab1 group by a, null, null
union all
select null, null, null, sum(d) from tab1 ;

group by後面不跟任何列求sum時,abc三列在聚合資料行會顯示為null。當列本身具有null值時,就會產生混淆,無法區分查詢結果中的null值是屬 於列本身的還是聚合的結果行,因此需要一種方法識別出列中的null值。grouping_id函式就是此場景下的解決方案。 這個函式為每種聚合資料行生成唯一的組id。它的返回值看起來像整型數值,其實是字串型別,這個值使用了點陣圖策略(bitvector,位向量),即它的二進位制形式中 的每一位表示對應列是否參與分組,如果某一列參與了分組,對應位就被置為1,否則為0。通過這種方式可以區分出資料本身中的null值。

遞迴(父子關係)

資料倉庫中的關聯實體經常表現為一種“父—子”關係

在這種型別的關係中,一個父親可能有多個孩子,而一個孩子只能屬於一個父親。例如,通常一名企業員工只 能被分配到一個部門,而一個部門會有很多員工。“父—子”之間形成一種遞迴型樹結構,是一種比較理想和靈活的儲存層次關係的資料結構

多路徑層次

描述

多路徑層次是對單路徑層次的擴充套件

如:資料倉庫的月維度只有一條層次路徑,即年-季度-月,新增一個 促銷期,加一個年-促銷期-月的層次路徑。這時月維度將有兩條層次路徑,因此是多路徑層次維度

參差不齊的層次

描述

上述例子中有的月份無促銷期

退化維度

描述

此技術可減少維度的數量,簡化維度資料倉庫模式,也有更好的查詢效能

維度表中除了業務主鍵外沒有其他內容,如:銷售訂單中,訂單維度表除了訂單號,沒有任何其他屬性,而訂單號是事務表的主鍵

雜項維度

描述

雜項維度就是一種包含的資料具有很少可能值的維度。

事務型商業過程通常產生一系列混雜的、低基數的標誌位或狀態資訊。與其為每個標誌或屬性定義不同的維度,不如建立單獨的將不同維度合併到一起的雜項維度。

屬性可能很多,但是每種屬性的可能值很少,只包含小範圍的離散值。

如:yes/no. 1/2

解決

  • 忽略這些標誌和指標
  • 保持事實錶行中的標誌位不變
  • 不建立對應的維表
  • 將每個標誌位放入其自己的維度中
  • 在裝載事實表資料前先處理這四個維度表,必要時生成新的代理鍵,然後在事實表中引用這些代理鍵
  • 將雜項維度當作普通維度來處理,多數情況下不合適

經驗值:外來鍵的數量不超過20

  • 雜項維度

雜項維度能夠合理地存放離散屬性值,還能夠維持其他主要維度地儲存空間

雜項維度是低基數標誌和指標的分組。通過建立雜項維度,可以將標誌和指標從事實表中移出,並將它們放入到有用的多維框架中

對雜項維度資料量的估算也會影響其建模策略

如:某個簡單的雜項維度包含10個二值標識,現金或信用卡支付型別、是否稽核、線上或離線、是否海外等,最多將包含1024(2^10)行。每個標誌都與其他標誌一起發生作用,在這種情況下,瀏覽單一維度內的標識可能沒什麼意義。

資料量不多,可預裝載,根據所有組合的笛卡爾積建立行

資料量太多,可根據事實表資料動態裝載

維度合併

描述

使用橋接表,將一個多對多關係轉化為兩個一對多關係。

事實表通過引用橋接表的一個代理鍵,同時關聯到多個維度值,這樣做的目的是消除資料冗餘,保證資料一致性

實現

將多對多關係根據笛卡爾積生成資料,並新增唯一標識列(主鍵)

分段維度

描述

有一些能夠定義成包含連續值的分段,例如年齡和收入這種數值型的屬性,就可以分 成連續的數值區間,而像狀態這種描述性的屬性,可能需要使用者根據自己的實際業務仔細定義,通常定義的根據是某種可度量的數值