2016-03-10 44 views
3

該錶的歷史數據變化:如何最好地處理在一個漸變維度(SCD2)

該公司爲我工作已經使用金博爾方法倉庫一個漸變維度(僱員數據)。包含此數據的維度表包含一個主鍵(int identity employee_key,用作其他表中的代理),自然鍵(employee_id),有效日期範圍(valid_dateinvalid_date)以及隨時間跟蹤的各種SCD1和SCD2數據元素。下面是一個簡化的例子:

employee_key | employee_id | valid_date | invalid_date | employee_name | employee_role 
1   | 1001  | 1/1/2015 | 6/1/2015  | Bob   | DBA 
2   | 1001  | 6/2/2015 | NULL   | Bob   | Developer 
3   | 1002  | 1/1/2015 | NULL   | Jill   | DBA 

在上述例子中,employee_key是主鍵(替代)和employee_id是自然鍵。其他值應該有希望是自我解釋。此表反映:

  1. Bob是從2015年1月1日開始到2015年6月1日結束的DBA。
  2. Bob是一名開發人員,開始於2015年6月2日,目前擔任該角色。
  3. Jill是從2015年1月1日開始的DBA,目前擔任該角色。

現在,我們也有一些參考這個維度的事實表。一個這樣的事實表包含了員工記錄的所有時間,並且細緻到當天。我們並不真正關注這些表的結構,只是使用代理鍵鏈接到我們的員工維度,並且他們通常包含很多行(在10M-200M之間)。下面是一個包含時間的事實表的示例記錄:

calendar_dt | employee_id | employee_key | time_code | hours 
1/1/2015 | 1001  | 1   | 1234  | 2.25 
1/1/2015 | 1001  | 1   | 21  | 3.50 
1/2/2015 | 1001  | 1   | 21  | 8.00 
... 
6/1/2015 | 1001  | 1   | 21  | 4.00 

通過代理鍵employee_key成爲一個重要的商業目的鏈接到員工層面 - 它能夠準確的歷史報告,而不昂貴的聯接使用BETWEEN操作。例如,它讓我們說,Bob在2015年6月1日記錄的時間可歸因於他的DBA角色,並且Bob在2015年6月2日記錄的時間可歸因於他的開發人員角色。

據我所知,這是一個有點標準的金球實施。

問題:

此實現不處理數據的修正很好。比方說,在我們之前的例子中,HR告訴我們Bob轉移到分析師角色的有效日期範圍爲2015年5月1日至2015年6月1日,並且他們未能將其輸入到系統中。這給我們帶來了一個主要問題:我們需要將employee_key = 1所在的行拆分成兩行,並使用不同的有效/無效日期。此外,我們需要找到現在錯誤地引用employee_key = 1並更新它們的所有地方。這裏是問題:

  1. 我們需要在一些巨大的表上運行昂貴的更新操作。每次需要進行更正時,我們都不能做到這一點。
  2. 尺寸行拆分需要手動完成,使表有數據輸入錯誤或有效/無效日期範圍重疊的風險。
  3. 拆分行違反了一條重要規則:主鍵是不可變的,一旦賦值就永遠不會改變。

解決方案:

我能想到的一些解決這一辦法的,但沒有一個是優雅:

  1. 與更新替代的關鍵數據的噩夢只是承擔。也許強制糾正發生在正常的時間表上,減少了我們運行此更新所需的次數。
  2. 將員工維度錶轉換爲每位員工每日行表。這具有允許在employee_idcalendar_dt上進行自然鍵連接的益處。它還使這個關鍵字不可變,並允許識別適當的代理關鍵字值,而無需在維度表中查找它。無論維度表如何變化,事實表將始終引用正確的行。這有一個主要缺點,即將我們的100,000行數據錶轉換爲20M行數據。

還有什麼其他解決方案?我不能成爲唯一遇到這個問題的人......幫幫我!

注意事項:

  • 我們作出這樣的數據將永遠需要一個時間要素(即粒度總是會在一天水平)的假設。
  • 我們假設employee_id值永遠不會改變(是的,我知道這是一個危險的假設)。

回答

1

您的DW有一個要求:「員工信息可隨時進行回顧性更改」,因此您的DW設計必須適應此情況。

可能有很多方法可以解決這個問題,但想到的最簡單的方法就是引入一個新的類型2集成表:master_employee_time。此表格將僅保留業務密鑰的原始時間記錄數據的版本歷史記錄。

employee_time_key | employee_id | valid_date | invalid_date | time date | time code | hours 
1     | 1001  | 1/1/2015 | NULL   | 1/1/2015 | 1234  | 2.25 
2     | 1001  | 1/1/2015 | NULL   | 1/1/2015 | 21  | 3.5 
3     | 1001  | 1/2/2015 | NULL   | 1/2/2015 | 21  | 8 

注:本表可能需要特殊的更新條件取決於你有多少時間片的數據訪問,也許限制在過去一年TYPE2變化time_dates然後手動處理任何舊的更新的要求。

一旦你有了這個表,可以通過master_employee和master_employee_time喜歡的東西

結合重建當前的事實表中的每個負載
insert into fact_employee_time 
select 
    t.calendar_dt, e.employee_id, e.employee_key, t.time_code, t.hours 
from 
    master_employee_time t 
    inner join master_employee e on t.employee_id = e.employee_id 
where 
    --limit to 'current' time recordings 
    t.invalid_date is null 
    and 
    --get the employee record active for the time recordings day 
    e.valid_date <= t.time_date 
    and 
    (e.invalid_date is null OR e.invalid_date >t.time_date) 

[解說] 這也爲您提供了能夠更新獎金同時爲那些不可避免的「爲什麼我的一月號碼有所改變」的需求,同時保留可審計的歷史記錄,同時要求「我必須能夠更改歷史數據」。 [/ comment]

相關問題