1. 程式人生 > >SQL Server 2008的Change Data Capture(變更資料捕獲)

SQL Server 2008的Change Data Capture(變更資料捕獲)

在常見的企業資料平臺管理中有一項任務是一直困擾SQL Server DBA們的,這就是對資料更新的監控。很多資料應用都需要捕獲對業務資料表的更新。筆者見過幾種解決方案:

1、在資料表中加入特殊的標誌列;
2、通過在資料表上建立觸發器;
3、通過第三方產品,例如Lumigent的Log Explorer。

其實第1種和第2中方案都不好,因為第1種方法需要在應用程式編碼的時候尤為小心,如果有一段資料訪問邏輯忘了更新標誌位就會導致遺漏某些資料更新,而第2種方法對效能影響過於明顯,因為觸發器的效能開銷是眾所周知的。第3種方法其實屬於一種叫做Log Audit的方案體系。因為SQL Server同其他關係型資料庫一樣,所有資料操作都會在日誌中記錄,因此通過分析日誌就可以獲得完整的資料操作歷史。SQL Server其實早就有內部的API可供ISV開發者中Log Audit的方案,不過微軟對這套API控制比較嚴格,只有簽署了一堆協議的核心級合作伙伴才能瞭解這套API。

因此,現對業務資料更新的跟蹤在SQL Server平臺上一直是一件非常頭疼的事情,使用者需要在投入大量開發精力和投入額外採購成本之間做出選擇。幸運的事,微軟終於在SQL Server 2008中提供了一套半公開的Log Audit機制,就是我們所說的Change Data Capture,我們後面簡稱CDC。

CDC的工作原理

我們前面說過CDC是通過分析日誌獲得資料操作歷史資訊的,那麼CDC的工作原理到底是怎麼樣的呢?下圖可以非常貼切地說明這個功能的原理:

◆當DML提交到應用資料庫時,SQL Server必須寫入日誌,並在快取中更新資料,然後在檢查點將記憶體中的資料刷回資料檔案。
◆CDC的內部程序根據CDC的設定,在日誌檔案中提取更新歷史資訊,並將這些個更新資訊寫入對應的更新跟蹤表。
◆DBA或開發人員通過呼叫CDC的函式來訪問更新跟蹤表,提取感興趣的更新歷史資訊,並通過ETL應用程式更新資料倉庫。
◆理論上面更新跟蹤表事會無限制增長的,因此CDC內部有一個清理程序,在預設情況下更新跟蹤資訊在寫入跟蹤表三天後會被自動清理。

CDC的配置

由於CDC是一項比較高階的功能,因此只有在SQL Server 2008的企業版、開發版和評估版中才能找到CDC功能。

啟用資料庫級別的CDC

要啟用CDC功能,首先需要一個sysadmin伺服器角色的成員使用者啟用資料庫級別的CDC。

USE testdb
GO
EXEC sys.sp_cdc_enable_db
GO

如果想知道一個數據庫是否啟用了CDC功能,可以通過查詢sys.databases系統目錄的is_cdc_enabled欄位。當一個數據庫啟用CDC功能後,SQL Server會自動在這個資料庫中建立cdc架構和cdc使用者,所有CDC相關的資料表和使用者函式都會存放在cdc架構下。

CDC功能啟用後,SQL Server會首先在cdc架構下建立五張表用於記錄一些CDC的原資料,分別是ddl_history,change_tables,captured_columns,index_columns和lsn_time_mapping。

資料庫啟用了CDC後,接下來我們就需要在資料表上啟用CDC了(需db_owner角色或sysadmin的使用者), 設定後,DBA可以查詢sys.tables系統目錄的is_tracked_by_cdc欄位

USE testdb
GO

EXEC sys.sp_cdc_enable_table
@source_schema = N'dbo',
@source_name   = N't_test_orders',  --源表名,  即將生成的"更改表"名為:  cdc.dbo_t_test_orders_CT,位於同一db下.
@role_name     = NULL,                        -- 需顯示指定是否要限定"更改表"的訪問角色.
@filegroup_name = N'PRIMARY',        --指定"更改表"存放的檔案組,以減少對"源表"檔案組的io影響
@supports_net_changes = 1               --啟用淨更新, "源表"必須有主鍵或唯一分鍵。查詢net_changes時會merge掉中間的更新,比較耗效能
--忽略了一個引數就是@captured_column_list,這個引數可以對錶中特定的某些欄位啟用更新跟蹤。
GO

"更改表"cdc.dbo_t_test_ordrs_CT,增加了_$start_lsn,_$end_lsn,_$seqval,_$operation和_$update_mask五個新的欄位. _$operation欄位是代表DML操作型別,1是delete,2是insert,3是update的舊值,4是update的新值。
$update_mask欄位是表示一個欄位列表的掩碼,那些在DML操作中被更新了的欄位位為1,而沒有更新的欄位位為0。如更新第1列就是0x01, 更新第1,2列就是0x11.

如果"源表"新增加了列需要跟蹤,需要先禁用,再啟用跟蹤.

USE testdb
GO
EXEC sys.sp_cdc_disable_table
@source_schema = N'dbo',
@source_name   = N't_test_orders',
@capture_instance = N'dbo_t_test_orders'       --注意不是更新表名"dbo_t_test_orders_CT", 少了CT
GO

查詢和操作"更改表": 

sys.fn_cdc_get_min_lsn,  sys.fn_cdc_get_max_lsn(),  cdc.lsn_time_mapping,  sys.fn_cdc_map_time_to_lsn()cdc.fn_cdc_get_all_changes*, cdc.fn_cdc_get_net_changes*

DECLARE @from_lsn binary(10), @to_lsn binary(10)
SET @from_lsn = sys.fn_cdc_get_min_lsn('dbo_t_test_orders')
SET @to_lsn   = sys.fn_cdc_get_max_lsn()
SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_t_test_orders(@from_lsn, @to_lsn, N'all')

CDC管理和監控

監視變更資料捕獲程序: select * from sys.dm_cdc_log_scan_sessions

變更資料捕獲日誌掃描會話期間遇到的每個錯誤: sys.dm_cdc_errors
捕捉作業:sp_MScdc_capture_job,   清除作業sp_MScdc_cleanup_job

對部署CDC的建議

◆CDC啟用會顯著增加日誌檔案的讀操作。
◆CDC啟用後更新跟蹤表會產生額外的寫入,並消耗儲存空間。
◆CDC啟用後,原資料表的聚簇索引尺寸會影響到CDC產生的IO資料量,而原始資料表上的非聚簇索引則不會。
◆CDC啟用後,被選定進行更新跟蹤的列鍵值屬性同樣會影響到CDC產生的IO資料量和儲存空間。