SQL Server 開啟CDC數據同步
1、 數據庫需要開啟代理服務。
開啟方式:
a). 點擊開始菜單àSQL Serverà配置管理工具àSQLserver服務àSQLserver代理à(右鍵)啟動
b). 打開電腦服務,找到SQLserver 代理,點擊左側狀態
2、 數據庫配置
a).首先查看數據庫是否已經開啟CDC服務
SELECT name,is_cdc_enabled FROM sys.databases WHERE is_cdc_enabled = 1;
返回已經開啟CDC的數據庫,如果為空,則所有的庫都沒有開啟CDC服務,轉到步驟b,對數據庫開啟CDC。如果有結果,則轉到步驟c。
b).對數據庫開啟CDC服務
USE test; -- 切換數據庫
EXECUTE sys.sp_cdc_enable_db; -- 開啟CDC功能
檢查是否開啟成功:
SELECT
is_cdc_enabled,
CASE WHEN is_cdc_enabled=0 THEN 'CDC功能禁用' ELSE 'CDC功能啟用' END 描述
FROM sys.databases
WHERE NAME = ‘test’ –- 你的數據庫名稱
創建成功后,將自動添加CDC用戶和CDC架構。
在用戶和架構下面可以看到cdc用戶和cdc架構
c.查看當前已經開啟CDC的數據表。
SELECT name,is_tracked_by_cdc FROM sys.tables WHERE is_tracked_by_cdc = 1;
d.開啟表CDC
sys.sp_cdc_enable_table
[ @source_schema = ] 'source_schema',
[ @source_name = ] 'source_name' ,
[ @role_name = ] 'role_name'
[,[ @capture_instance = ] 'capture_instance' ]
[,[ @supports_net_changes = ] supports_net_changes ]
[,[ @index_name = ] 'index_name' ]
[,[ @captured_column_list = ] 'captured_column_list' ]
[,[ @filegroup_name = ] 'filegroup_name' ]
[,[ @partition_switch = ] 'partition_switch' ]
示例:
對'USRALMHS'表開啟變更捕獲
EXEC sys.sp_cdc_enable_table
@source_schema= 'dbo', --源表架構
@source_name = 'USRALMHS', --源表
@role_name = 'CDC_Role' --角色(將自動創建)
GO
--如果不想控制訪問角色,則@role_name必須顯式設置為null。
查詢是否成功
SELECT name ,
is_tracked_by_cdc ,
CASE WHEN is_tracked_by_cdc = 0 THEN 'CDC功能禁用'
ELSE 'CDC功能啟用'
END 描述
FROM sys.tables
WHERE OBJECT_ID = OBJECT_ID('dbo. USRALMHS ')
對表開啟成功后,可以查看數據庫,在數據庫系統表下增加了很多表。
在SQLserver 代理中多了兩個作業
在可編程性-》函數-》表值函數里,也多了兩個函數
3、 測試
a) 向表中插入數據
insert into test.dbo.USRALMHS select top 1000 * from alarm.dbo.USRALMHS_copy3
在DBO_USRALMHS_CT中查看:
會有同樣的1000 條數據,唯一不同的是在DBO_USRALMHS_CT中會多幾個字段,分別代表不同的含義,其中最主要的是 __$operation 代表含義 1 刪除、2插入、3更新前的內容、4更新后的內容 @bglsn 開始時間的時間戳 @edlsn 結束時間的時間戳
b) 測試更新和刪除操作(生成數據的__$operation 不同)
省略
4、 分析(系統自帶數據庫)
a) 分析存儲過程
---查詢當前作業配置
SELECT * FROM MSDB.dbo.cdc_jobs
--或者使用
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_help_jobs;
GO
1.sys.sp_cdc_add_job
在當前數據庫中創建變更數據捕獲清理或捕獲作業
1.創建捕獲作業
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_add_job
@job_type = N'capture';
GO
2.創建清理作業
---創建清理作業,作業連續運行,更改數據行將在更改表中保留2880分鍾,清除時使用一條語句最多刪除4000條記錄
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_add_job
@job_type = N'cleanup'
,@start_job=1
,@retention=2880
,@threshold =4000
2.sys.sp_cdc_change_job
修改當前數據庫中變更數據捕獲清除或捕獲作業的配置
--僅在使用 sp_cdc_stop_job 停止作業並使用 sp_cdc_start_job 重新啟動該作業后,對該作業所做的更改才會生效
1.更改捕獲作業
--將每個循環掃描最多處理的事務數更改為200,為了從日志中提取所有行而要執行的最大掃描循環50次
USE AdventureWorks2008R2;
GO
EXECUTE sys.sp_cdc_change_job
@job_type = N'capture',
@maxtrans = 200,
@maxscans = 50;
GO
2.更改清除作業,將記錄保留時間更改為3440分鍾
USE AdventureWorks2008R2;
GO
EXECUTE sys.sp_cdc_change_job
@job_type = N'cleanup',
@retention = 3440;
GO
3.sys.sp_cdc_cleanup_change_table
根據指定的 low_water_mark 值從當前數據庫的更改表中刪除行,重置更改表中的最小 __$start_lsn,並刪除小於該值的數據.
將同時清除cdc.HR_Department_CT,cdc.lsn_time_mapping表的記錄
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_cleanup_change_table
@capture_instance =N'HR_Department',
@low_water_mark=0x0000037D000000D30008,
@threshold=2000;
SELECT sys.fn_cdc_increment_lsn(sys.fn_cdc_get_max_lsn())
4.sys.sp_cdc_drop_job
從 msdb 中刪除當前數據庫的變更數據捕獲清除或捕獲作業。
--下例刪除 AdventureWorks2008R2 數據庫的清除作業和捕獲作業
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_drop_job @job_type = N'cleanup';
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_drop_job @job_type = N'capture';
5.sys.sp_cdc_disable_db
對當前數據庫禁用變更數據捕獲
禁用當前對數據庫中的所有表啟用的變更數據捕獲。與變更數據捕獲相關的所有系統對象(如更改表、作業、存儲過程和函數)都將被刪除。sys.databases 目錄視圖中的數據庫條目的 is_cdc_enabled 列設置為 0。
如果在禁用變更數據捕獲時為數據庫定義了很多捕獲實例,則長時間運行事務可能導致 sys.sp_cdc_disable_db 的執行失敗。通過在運行 sys.sp_cdc_disable_db 之前使用 sys.sp_cdc_disable_table 禁用單個捕獲實例,可以避免此問題。
USE AdventureWorks2008R2;
GO
EXECUTE sys.sp_cdc_disable_db;
GO
6.sys.sp_cdc_disable_table
對當前數據庫中指定的源表和捕獲實例禁用變更數據捕獲
刪除與指定的源表和捕獲實例相關聯的變更數據捕獲更改表和系統函數。它會刪除任何與來自變更數據捕獲系統表的指定捕獲實例相關聯的行,並將 sys.tables 目錄視圖中的表項的 is_tracked_by_cdc 列設置為 0。
---下例對 HumanResources.Department 表禁用了變更數據捕獲
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_disable_table
@source_schema = N'HumanResources'
, @source_name = N'Department'
, @capture_instance = N'HR_Department' ---這里是定義的實例名稱,在一開始創建捕獲的時候創建的,這里也可以制定ALL(禁用表HumanResources.Department的所有捕獲),
7.sys.sp_cdc_enable_db
對當前數據庫啟用變更數據捕獲。必須先對數據庫執行此過程,然后才能對該數據庫中的任何表啟用變更數據捕獲。變更數據捕獲可記錄應用到所啟用的表中的插入、更新和刪除活動,同時采用易於使用的關系格式提供變更詳細信息。此操作將為已修改的行捕獲反映了所跟蹤源表列結構的列信息,同時還捕獲將更改應用到目標環境所需的元數據。
將創建以全數據庫為作用域的變更數據捕獲對象,包括元數據表和 DDL 觸發器。它還會創建 cdc 架構和 cdc 數據庫用戶,並將 sys.databases 目錄視圖中的數據庫條目的 is_cdc_enabled 列設置為 1。
USE AdventureWorks2008R2;
GO
EXECUTE sys.sp_cdc_enable_db;
GO
8.sys.sp_cdc_enable_table
--對需要進行跟蹤的表啟動CDC,sys.sp_cdc_enable_table
/*
為當前數據庫中指定的源表啟用變更數據捕獲。對表啟用變更數據捕獲時,應用於此表的每個數據操縱語言 (DML) 操作的記錄都將寫入事務日志中。
變更數據捕獲進程將從日志中檢索此信息,並將其寫入可通過使用一組函數訪問的更改表中。
*/
sys.sp_cdc_enable_table
[ @source_schema = ] 'source_schema', ---表所屬的架構名
[ @source_name = ] 'source_name' ,----表名
[ @role_name = ] 'role_name'---是用於控制更改數據訪問的數據庫角色的名稱。
[,[ @capture_instance = ] 'capture_instance' ]--是用於命名特定於實例的變更數據捕獲對象的捕獲實例的名稱
[,[ @supports_net_changes = ] supports_net_changes ]---指示是否對此捕獲實例啟用凈更改查詢支持
[,[ @index_name = ] 'index_name' ]--用於唯一標識源表中的行的唯一索引的名稱。index_name 為 sysname,並且可以為 NULL。如果指定,則 index_name 必須是源表的唯一有效索引。如果指定 index_name,則標識的索引列優先於任何定義的主鍵列,就像表的唯一行標識符一樣。
[,[ @captured_column_list = ] 'captured_column_list' ]--需要對哪些列進行捕獲。captured_column_list 的數據類型為 nvarchar(max),並且可以為 NULL。如果為 NULL,則所有列都將包括在更改表中。
[,[ @filegroup_name = ] 'filegroup_name' ]--是要用於為捕獲實例創建的更改表的文件組。
[,[ @partition_switch = ] 'partition_switch' ]--指示是否可以對啟用了變更數據捕獲的表執行 ALTER TABLE 的 SWITCH PARTITION 命令。allow_partition_switch 為 bit,默認值為 1。
9.sp_cdc_generate_wrapper_function
生成用於為 SQL Server 中可用的變更數據捕獲查詢函數創建包裝函數的腳本
EXEC sys.sp_cdc_generate_wrapper_function
10. sys.sp_cdc_help_change_data_capture
返回當前數據庫中為變更數據捕獲啟用的每個表的變更數據捕獲配置。最多可為每個源表返回兩行,為每個捕獲實例返回一行。
---返回制定表的捕獲信息
USE AdventureWorks2008R2;
GO
EXECUTE sys.sp_cdc_help_change_data_capture
@source_schema = N'HumanResources', --架構名
@source_name = N'Department';--表名
GO
--返回所有表的捕獲信息
USE AdventureWorks2008R2;
GO
EXECUTE sys.sp_cdc_help_change_data_capture
11.sys.sp_cdc_get_captured_columns
返回指定捕獲實例所跟蹤的捕獲源列的變更數據捕獲元數據信息。
USE AdventureWorks2008R2;
GO
EXECUTE sys.sp_cdc_get_captured_columns
@capture_instance = N'HR_Department';
GO
12.sys.sp_cdc_get_ddl_history
返回自對指定的捕獲實例啟用變更數據捕獲后與該捕獲實例關聯的數據定義語言 (DDL) 更改歷史記錄。
與查詢表是一樣的結果
SELECT * FROM cdc.ddl_history
USE AdventureWorks2008R2;
GO
EXECUTE sys.sp_cdc_get_ddl_history
@capture_instance = N'HR_Department';
13.sp_cdc_help_jobs
報告關於當前數據庫中所有變更數據捕獲清除或捕獲作業的信息。因為一個數據庫只會在第一個表創建捕獲的時候創建作業
所以這里只需要在當前庫執行就可以。
sys.sp_cdc_help_jobs
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_help_jobs;
GO
14.sp_cdc_scan
執行變更數據捕獲日志掃描操作,需要進行捕獲的時候使用,默認情況下5會自動進行捕獲。
如果變更數據捕獲正在使用 SQL Server 代理捕獲作業,則 sys.sp_MScdc_capture_job 將內部調用 sys.sp_cdc_scan。如果變更數據捕獲日志掃描操作已經處於活動狀態,或數據庫啟用了事務復制,則無法顯式執行此過程。此存儲過程應當由需要自定義自動配置的捕獲作業的行為的管理員使用。
USE AdventureWorks2008R2;
GO
EXEC sp_cdc_scan
15.sys.sp_cdc_start_job,
啟動和停止當前數據庫的變更數據捕獲清除或捕獲作業。
---啟動清除作業
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_start_job @job_type = N'cleanup';
---停止捕獲作業
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_stop_job @job_type = N'capture';
GO
USE AdventureWorks2008R2;
GO
EXEC sys.sp_cdc_stop_job @job_type = N'cleanup';
GO
b) 分析函數
1.fn_cdc_get_all_changes_capture_instance
針對在指定日志序列號 (LSN) 范圍內應用到源表的每項更改均返回一行
USE AdventureWorks2008R2;
GO
DECLARE @from_lsn binary(10), @to_lsn binary(10)
SET @from_lsn =
sys.fn_cdc_get_min_lsn('HR_Department')
SET @to_lsn = sys.fn_cdc_get_max_lsn()
SELECT * FROM cdc.fn_cdc_get_all_changes_HR_Department
(@from_lsn, @to_lsn, N'all');
GO
2.fn_cdc_get_net_changes_capture_instance
針對指定 LSN 范圍內每個已更改的源行返回一個凈更改行。也就是說,如果在 LSN 范圍內源行具有多項更改,
則該函數將返回反映該行最終內容的單一行。例如,如果事務在源表中插入一行,並且 LSN 范圍內的后續事務更新了該行中的一個或多個列,
則該函數將只返回一行,其中包含多個更新的列值。
如果值最后是刪除操作,則不返回該LSN的值
USE AdventureWorks2008R2;
GO
DECLARE @begin_time datetime, @end_time datetime, @from_lsn binary(10), @to_lsn binary(10);
-- Obtain the beginning of the time interval.
SET @begin_time = GETDATE() -1;
-- DML statements to produce changes in the HumanResources.Department table.
INSERT INTO HumanResources.Department (Name, GroupName)
VALUES (N'MyDept', N'MyNewGroup');
UPDATE HumanResources.Department
SET GroupName = N'Resource Control'
WHERE GroupName = N'Inventory Management';
DELETE FROM HumanResources.Department
WHERE Name = N'MyDept';
-- Obtain the end of the time interval.
SET @end_time = GETDATE();
-- Map the time interval to a change data capture query range.
SET @from_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than or equal', @begin_time);
SET @to_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
-- Return the net changes occurring within the query window.
SELECT * FROM cdc.fn_cdc_get_net_changes_HR_Department(@from_lsn, @to_lsn, 'all');
3.sys.fn_cdc_decrement_lsn
根據指定的 LSN 返回序列中的上一個日志序列號 (LSN)
Use AdventureWorks2008R2;
GO
SELECT sys.fn_cdc_decrement_lsn(sys.fn_cdc_get_max_lsn())
下例在一個返回 LSN 值小於最大 LSN 值的更改數據行的查詢中,使用 sys.fn_cdc_decrement_lsn 來設置 LSN 上限。
Use AdventureWorks2008R2;
GO
DECLARE @from_lsn binary(10), @to_lsn binary(10);
SET @from_lsn = sys.fn_cdc_get_min_lsn('HR_Department');
SET @to_lsn = sys.fn_cdc_decrement_lsn(sys.fn_cdc_get_max_lsn());
SELECT * FROM cdc.fn_cdc_get_net_changes_HR_Department( @from_lsn, @to_lsn, 'all');
GO
4.sys.fn_cdc_increment_lsn
根據指定的 LSN 返回序列中的下一個日志序列號 (LSN)。
此函數返回的 LSN 值始終大於指定的值,並且不存在介於這兩個值之間的 LSN 值。
若要系統地查詢隨時間變化的更改數據流,可以定期重復調用該查詢函數,每次調用時指定一個新的查詢間隔來限定查詢中返回的更改的范圍。為幫助確保不丟失數據,通常使用前一個查詢的上限來生成后一個查詢的下限。由於查詢間隔是一個閉區間,因此新的下限必須大於前一個上限,但要足夠小,以確保不存在 LSN 值介於此值與舊上限之間的更改。sys.fn_cdc_increment_lsn 函數就是用來獲取此值的。
Use AdventureWorks2008R2;
GO
SELECT sys.fn_cdc_increment_lsn(sys.fn_cdc_get_max_lsn())
5.sys.fn_cdc_get_column_ordinal
返回實例制定列的列序號。
Use AdventureWorks2008R2;
GO
SELECT sys.fn_cdc_get_column_ordinal ( 'HR_Department','NAME');
6.sys.fn_cdc_get_max_lsn
返回 cdc.lsn_time_mapping 系統表的 start_lsn 列中的最大日志序列號 (LSN)。您可以使用此函數為任何捕獲實例返回變更數據捕獲時間線的高端點
USE AdventureWorks2008R2;
GO
SELECT sys.fn_cdc_get_max_lsn()AS max_lsn;
SELECT sys.fn_cdc_get_min_lsn(N'HR_Department');
USE AdventureWorks2008R2;
GO
DECLARE @from_lsn binary(10), @to_lsn binary(10);
SET @from_lsn = sys.fn_cdc_get_min_lsn(N'HR_Department');
SET @to_lsn = sys.fn_cdc_get_max_lsn();
SELECT * FROM cdc.fn_cdc_get_net_changes_HR_Department(@from_lsn, @to_lsn, 'all');
GO
7.sys.fn_cdc_get_min_lsn
USE AdventureWorks2008R2;
GO
SELECT sys.fn_cdc_get_min_lsn ('HR_Department')AS min_lsn;---查詢制定的實例名的最小LSN
8.sys.fn_cdc_has_column_changed ( 'capture_instance','column_name' , update_mask )
標識指定的更新掩碼是否指示已更新關聯的更改行中的指定列。
USE AdventureWorks2008R2;
GO
SELECT sys.fn_cdc_has_column_changed ('HR_Department','name' , 2)
9.sys.fn_cdc_is_bit_set
指示捕獲的列是否已更新,采用的方法是檢查是否在提供的位掩碼內設置了其序號位置。
USE AdventureWorks2008R2;
GO
DECLARE @from_lsn binary(10), @to_lsn binary(10), @GroupNm_ordinal int;
SET @from_lsn = sys.fn_cdc_get_min_lsn('HR_Department');
SET @to_lsn = sys.fn_cdc_get_max_lsn();
SET @GroupNm_ordinal = sys.fn_cdc_get_column_ordinal('HR_Department','GroupName');
SELECT sys.fn_cdc_is_bit_set(@GroupNm_ordinal,__$update_mask) as 'IsGroupNmUpdated', *
FROM cdc.fn_cdc_get_all_changes_HR_Department( @from_lsn, @to_lsn, 'all')
WHERE __$operation = 4;
GO
10.sys.fn_cdc_map_lsn_to_time
為指定的日志序列號 (LSN) 返回 cdc.lsn_time_mapping 系統表的 tran_end_time 列中的日期和時間值。
您可以使用此函數系統地將 LSN 范圍映射到更改表中的日期范圍
SELECT sys.fn_cdc_map_lsn_to_time(sys.fn_cdc_get_max_lsn());
11.sys.fn_cdc_map_time_lsn
下面的示例使用 sys.fn_cdc_map_time_lsn 函數來確定在 cdc.lsn_time_mapping 表中是否有 tran_end_time
值大於或等於指定時間的行。例如,可以用此查詢來確定捕獲進程是否已處理完截至前指定時間提交的更改
DECLARE @extraction_time datetime, @lsn binary(10);
SET @extraction_time = GETDATE();
SELECT @lsn = sys.fn_cdc_map_time_to_lsn ('smallest greater than or equal', @extraction_time);
IF @lsn IS NOT NULL
BEGIN
print '...'
END
DECLARE @begin_time datetime, @end_time datetime, @begin_lsn binary(10), @end_lsn binary(10);
SET @begin_time = '2015-04-07 18:00:00.000';
SET @end_time = '2015-04-08 18:00:00.000';
SELECT @begin_lsn = sys.fn_cdc_map_time_to_lsn('smallest greater than', @begin_time);
SELECT @end_lsn = sys.fn_cdc_map_time_to_lsn('largest less than or equal', @end_time);
SELECT * FROM cdc.fn_cdc_get_net_changes_HR_Department(@begin_lsn, @end_lsn, 'all ');
c) 分析系統視圖
1.sys.dm_cdc_log_scan_sessions
針對當前數據庫中的每個日志掃描會話返回一行。返回的最后一行表示當前會話。您可以使用此視圖返回有關當前日志掃描會話的狀態信息,
或有關自 SQL Server 實例上次啟動以來所有會話的聚合信息。
USE AdventureWorks2008R2;
SELECT *
FROM sys.dm_cdc_log_scan_sessions
--可以觀察empty_scan_count字段的值可以發現它的變化,5秒增加一次,和前面配置的日志掃描作業的頻率是一樣的
USE AdventureWorks2008R2;
GO
print getdate()
SELECT empty_scan_count
FROM sys.dm_cdc_log_scan_sessions
WHERE session_id = (SELECT MAX(b.session_id) from sys.dm_cdc_log_scan_sessions AS b)
waitfor DELAY '00:01'
print getdate()
SELECT empty_scan_count
FROM sys.dm_cdc_log_scan_sessions
WHERE session_id = (SELECT MAX(b.session_id) from sys.dm_cdc_log_scan_sessions AS b)
2.sys.dm_cdc_errors
為變更數據捕獲日志掃描會話中遇到的每個錯誤返回一行。
USE AdventureWorks2008R2;
GO
SELECT *
FROM sys.dm_cdc_errors