開篇介紹
通常在數據量較少的情況下,我們從一個數據源將全部數據加載到目標數據庫的時候可以采取的策略可以是:先將目標數據庫的數據全部清空掉,然后全部重新從數據源加載進來。這是一個最簡單並且最直觀的並且不容易出錯的一種解決方案,但是在很多時候會帶來性能上的問題。
如果我們的數據源來自於不同的業務系統,數據動輒百萬,千萬甚至億級計算。第一次需要全部加載,如果在第二次周期或者第三次周期的時候仍然全部加載的話,耗費了極大的物理和時間資源。有可能部分數據源並未發生變化,而有的數據源可能只是增加了少量的數據。
我們要考慮的問題是,對於已經存在目標數據庫中的數據都是歷史數據,對於數據源中的數據我們只應該考慮新修改的記錄和新插入的記錄,只應該考慮這兩種數據。所以增量處理實質上就是處理變化的數據。
下面我們一起看看這些表,忽略從數據倉庫設計的角度,只考慮如何實現增量數據的檢測和抽取。
第一類 - 具有時間戳或者自增長列的絕對歷史數據表
這張表能夠代表一部分數據源的特征 - 絕對歷史事實數據。它指的是表中的數據是不可逆的,只有插入操作沒有刪除或者修改操作,表示在過去一段時間內完成的事實業務數據。比如這張表表示的某些產品的下載信息,用戶什么時候下載了產品就會在數據庫中記錄一條數據。
這種數據表一般會提供一列能夠記載這條記錄生成的歷史時間,或者說這個操作發生的時間,越早的操作時間越靠前,越晚的操作時間越靠后。
那么對於這類表的增量處理策略就是:
- 第一次加載動作完成之后,記錄一下最大的時間點,保存到一個加載記錄表中。
- 從第二次加載開始先比較上次操作保存的最后/最大的時間點,只加載這個時間點以后的數據。
- 當加載過程全部成功完成之后再更新加載記錄表,更新這次最后的時間點。
另外,如果這類表有自增長列的話,那么也可以使用自增長列來實現這個標識特征。
第二類 - 有修改時間特征的數據表
這類表中的數據一般屬於可以修改帶有維護性質的數據,比如像會員信息表,創建會員的時候會生成一條記錄,會在 CreateDate 標記一下,並且在 UpdateDate 中保存的也是 CreateDate 的值。當 CreateDate 和 UpdateDate 相同的時候說明這一條數據是插入操作,但是這個會員的信息是可以被編輯和修改的,於是每次更新的同時也更新了 UpdateDate 時間戳。
假設上面的這幾條數據在第一次加載到目標數據庫后,源表新加入了一條會員記錄並同時修改了一條會員的信息。
那么像這種情況下增量數據處理的策略就可以是:
- 第一次加載動作完成以后,記錄一下最大的 UpdateDate 時間戳,保存到一個加載記錄表中。(第一次是 2010-10-23)
- 在第二次加載數據的時候,用加載記錄表中的時間戳與源表里的 UpdateDate 相比較,比時間戳大的說明是新添加的或者修改的數據。(大於 2010-10-23 的是第一條 Update 的數據和第四條新增的數據)
- 當整個加載過程成功之后,更新最大的 UpdateDate到記錄表中。(記錄表中將 2010-10-26 記錄下來)
但是要注意的是,不是每一個帶有修改時間特征的數據表都會這么設計,有可能在插入數據的時候只會放入 CreateDate 但是並不會寫入 UpdateDate。這樣的話,在每次加載的過程中可能就需要同時比較 CreateDate 和 UpdateDate 了。
第三類 - 關聯編輯信息的無時間特征數據表
這類表本身沒有任何可以標識的自增長 ID 或者時間戳,只保留基本信息,所有的編輯操作等信息專門有一張表來記錄。這樣的設計可以是為了單獨記載所有的編輯歷史信息,但是同時又保留了主要信息的獨立性,在查詢主表的時候查詢體積變小提供查詢效率。類似於這樣的設計可以參照第一類和第二類的設計方案,在這個示例中多出的就是要關聯 Member Audit History 表並進行時間戳或者自增長ID 的判斷。
第四類 - 無特征數據表
很少有人這樣設計數據表,但是不代表不存在。我曾經碰到過一個文件表,由於部分數據的敏感性不能直接訪問源數據庫,因此是由客戶從源數據庫將數據抽取出來保存到一個文本文件中。很遺憾的是,抽取出來的數據中只保留了創建時間,但是並沒有任何能夠標識修改行為的列。與客戶的溝通到最終客戶接受意見修改,到最終修改完成這中間是沒法停下來等客戶的,因此只能暫時采用另外的一種方法 - 基於唯一列的數據對比。
很簡單的概念 - 即每次加載數據源中的數據時,基於主鍵或者唯一列到目標表中查詢是否存在,如果不存在就插入。如果存在就比較關鍵列數據是否相等,不相等就修改。
這種實現可以采用 SQL Merge 語句來完成 - 請參看- SQL Server - 使用 Merge 語句實現表數據之間的對比同步
或者通過 SSIS 中的 Lookup + Conditional Split 實現 - 請參看-SSIS 系列 - 數據倉庫中實現 Slowly Changing Dimension 緩慢漸變維度的三種方式
那么對於前三類數據表,它們可以共同使用一個加載記錄表來記錄它們上一次的時間戳或者自增 ID。
對於 Table A -
SELECT 列1, 列2 FROM Table_A WHERE ID > (SELECT LastSeqID FROM SourceLoadingAudit WHERE SourceTable = 'Table_A ')
對於 Table C -
SELECT 列1, 列2 FROM Table_C WHERE UpdateDate > (SELECT LastModifiedDate FROM SourceLoadingAudit WHERE SourceTable = 'Table_C')
數據倉庫增量數據處理
數據倉庫增量數據處理一般發生在從 Source 到 Staging 的過程中,從 Staging 到DW 一般又分為維度 ETL 處理和事實 ETL 處理兩個部分。那么實際上從 Source 到 Staging 的過程中,就已經有意識的對維度和事實進行了分類加載處理。通常情況下,作為維度的數據量較小,而作為業務事實數據量通常非常大。因此,着重要處理的是業務事實數據,要對這一部分數據采取合適的增量加載策略。
通常情況下,對數據倉庫從 Source 到 Staging 增量數據的處理可以按照這種方式:
- 對於具有維度性質的數據表可以在 Staging 中采取全卸載,全重新加載的模式。即每次加載數據的時候,先將 Staging 表數據清空掉,然后再重新從數據源加載數據到 Staging 表中。
- 對於具有事實性質的數據表,需要考慮使用上面通用的集中增量數據處理的方案,選擇一個合適的方式來處理數據。保證在 Staging 事實中的數據相對於后面的 DW 數據庫來說就是新增的或者已修改過的數據。
但是也不排除大維度表的情況出現,即具有維度性質的數據表本身就非常龐大,像會員表有可能作為維度表,動輒百萬甚至千萬的數據。這種情況下,也可以考慮使用合適的增量數據加載策略來提高加載的性能。
至於從 Staging 到 DW 的這一過程,通常情況下包含了維度 SCD 過程和事實 Lookup 過程,這個在后面再陸續寫。關於緩慢漸變維度 Slowly Change Dimension 的相關理論文章可以查看我的這篇博客 - 數據倉庫系列 - 緩慢漸變維度 (Slowly Changing Dimension) 常見的三種類型及原型設計
在 SSIS 中的實現可以參看我的這篇博客 - SSIS 系列 - 數據倉庫中實現 Slowly Changing Dimension 緩慢漸變維度的三種方式
其它的加載策略
增量加載的處理策略不是一成不變的,采取哪一種加載策略跟數據源的設計有很大的關系。良好的數據源設計可能直接就給后續的增量處理提供了最直接的判斷依據,比如自增長列,時間日期戳等。還有的數據源設計可能加入了觸發器,在數據新增,修改或者刪除的過程中就做出了有效的日志記錄。或者加入了一些審核表,在數據的增刪改過程中記錄並跟蹤了數據的操作細節,那么這樣也是可以變通的采用上面的幾種增量加載策略來設計符合當前系統的流程。
如何在增量加載之上更進一步?
還有一個非常重要的問題就是:如何處理在增量加載過程中失敗的情況? 比如從 Source 到 Staging 的過程總共需要將數據寫入到10個不同的 Staging 表,但是在數據加載的過程中由於一些意外情況導致其中5個表加載失敗,其它5個表成功。由於考慮到效率問題,不想每次都重新加載,因此可以考慮采用以下兩種方式:
第一種方式 - SSIS Package 過程處理日志和錯誤日志模式
在每次 SSIS Package 執行的時候,寫入一條記錄到 ProcessLog 中,ExecutionStatus = 0 表示開始。執行成功的時候,更新 ExecutionStatus = 1 表示成功。執行失敗的時候,更新 ExecutionStatus = -1 同時在 Event Handlers 中記錄一條 Error Log 來記錄一些錯誤信息。
下面這張表反映了在 ProcessLogID = 372 這一批次增量加載的 Audit 信息表,當然甚至可以添加加載的條數等等信息。Process Log ID = 372 的在 Process Log 表中反映出來的是一次成功的執行。
第二次執行的時候就會去檢查是否執行失敗的 Process Log ,如果沒有的話就根據 LastSegID 或者 LastModifiedDate 完成增量加載。
第三次執行的時候,發現 Audit 表中第二次有兩條沒有執行成功,因此只會對上次沒有成功的兩個表再次加載數據。
第二種方式 - SSIS Package 中的檢查點
具體內容可以參看 - SSIS 系列 - 通過設置 CheckPoints 檢查點來增強 SSIS Package 流程的重用性
通過這兩種方式,可以使我們的數據加載流程更加合理一些。通過增量數據的加載模式減少了一部分不必要的數據加載提升了性能,那么在這個基礎之上通過日志和檢查點模式在增量模式之上提高了加載過程的可重用性。已經加載過的,不再重復加載。加載失敗了的,重新加載,這樣對包的性能和健壯性又是一種提升。
不足之處就是第二次加載之后,由於有兩個表加載成功,另外兩張表加載失敗。因此等失敗的表重新加載之時數據源可能已經發生變化,這樣造成成功與失敗的表面對的數據源有所不一致,這一點在設計階段需要考慮,這種變化是否在允許的范圍內。
總結
增量數據加載的策略與數據源有莫大的關系,也與實際需求有莫大關系,因此在設計增量數據加載的過程中需要圍繞實際需求以及數據源能夠提供的增量變化特征仔細思考,甚至反復測試來達到加載機制的穩定和可靠性。
上面都是本人在各個不同的項目中的實際總結,數據表格定義以及思路方面只供參考。具體實現因項目不同也會存在一些差異,但這些精簡過的思路可供嘗試,歡迎大家補充。
最后補充一下,在這個帖子里有關於增量實現的部分內容,可以參考一下 - SSIS 系列 - 在 SSIS 中使用 Multicast Task 將數據源數據同時寫入多個目標表,以及寫入Audit 與增量處理信息
更多 BI 文章請參看 BI 系列隨筆列表 (SSIS, SSRS, SSAS, MDX, SQL Server) 如果覺得這篇文章看了對您有幫助,請幫助推薦,以方便他人在 BIWORK 博客推薦欄中快速看到這些文章。