https://docs.microsoft.com/zh-cn/previous-versions/sql/sql-server-2008/cc280519(v=sql.100)?redirectedfrom=MSDN
https://bbs.csdn.net/topics/280034032
经常会有需求记录用户表中由DML操作(Insert/Updae/Delete)引起的数据变化,在SQL Server 2008 以前的版本中,要实现这样的功能只能通过Trigger或者数据比对(例如SCD处理),而且必须针对每个用户表开发。SQL Server 2008中新增了两种记录数据变化的功能,本文就Change Data Capture(CDC)和Change Tracking的特性做简要对比。
Change Data Capture
CDC通过对事务日志的异步读取,记录DML操作的发生时间、类型和实际影响的数据变化,然后将这些数据记录到启用CDC时自动创建的表中。通过cdc相关的存储过程,可以获取详细的数据变化情况。由于数据变化是异步读取的,因此对整体性能的影响不大,远小于通过Trigger实现的数据变化记录。
Change Tracking
不同于Change Data Capture,Change Tracking仅记录DML操作的发生时间、类型和影响到的字段,不包含具体的变化数值,客户端通过传传递上次同步的版本号来获取从上次同步到现在的变化记录。对于应用数据缓存的场合,这个功能非常实用,可以每隔一定时间获取数据表中的变化记录,然后根据变化记录中的主键来获取更新过的数据从而刷新缓存。
Change Tracking通过对要执行的DML语句的分析获取变化记录,而不是去读取日志。DML语句提交执行时Change Tracking便已可用,而不需要等待DML完成后事务日志写入时才可用,因此Change Tracking的响应比Change Data Capture要快。
Change Tracking记录的数据比Change Data Capture少,对服务器性能的影响也小。
具体代码如下:
--1、整个数据使用变化跟踪
ALTER DATABASE sql2008 SET Change_Tracking = ON(CHANGE_RETENTION = 2 MINUTES, AUTO_CLEANUP = ON)
GO
CREATE TABLE TestCT(ID int PRIMARY KEY, Name varchar(50), Description varchar(200))
GO
--2、对表TestCT启动变化跟踪
ALTER TABLE TestCT ENABLE CHANGE_TRACKING WITH(TRACK_COLUMNS_UPDATED = ON)
GO
SELECT OBJECT_NAME(object_id) AS table_name, sys.change_tracking_tables.* FROM sys.change_tracking_tables
--Table||object_id||is_track_columns_updated_on||min_valid_version||begin_version||cleanup_version
--TestCT 709577566 0 0 0 0
SELECT CHANGE_TRACKING_CURRENT_VERSION() AS current_version
--操作前版本号是0
INSERT INTO TestCT VALUES (1, 'ABC', NULL)
INSERT INTO TestCT VALUES (2, 'XYZ', NULL)
--插入数据后版本号是2
SELECT CHANGE_TRACKING_CURRENT_VERSION() AS current_version
SELECT * FROM CHANGETABLE(CHANGES TestCT, 0) CT
--在同一个事物中插入数据
BEGIN TRAN
INSERT INTO TestCT VALUES (3, 'CBA', NULL)
INSERT INTO TestCT VALUES (4, 'ZYX', NULL)
COMMIT
--每个事物是一个版本号,结果是3
SELECT CHANGE_TRACKING_CURRENT_VERSION() AS current_version
SELECT * FROM CHANGETABLE(CHANGES TestCT, 2) CT
--3 3 I NULL NULL 3
--3 3 I NULL NULL 4
UPDATE TestCT SET Name = 'abc' WHERE ID = 1
SELECT CHANGE_TRACKING_CURRENT_VERSION() AS current_version
--结果是4
SELECT * FROM CHANGETABLE(CHANGES TestCT, 0) CT --
SELECT * FROM CHANGETABLE(CHANGES TestCT, 3) CT --
SELECT CHANGE_TRACKING_IS_COLUMN_IN_MASK
(COLUMNPROPERTY(OBJECT_ID('TestCT'), 'Name', 'ColumnId'), SYS_CHANGE_COLUMNS)
AS is_column_Name_changed,
CHANGE_TRACKING_IS_COLUMN_IN_MASK
(COLUMNPROPERTY(OBJECT_ID('TestCT'), 'Description', 'ColumnId'), SYS_CHANGE_COLUMNS)
AS is_column_Description_changed
FROM CHANGETABLE(CHANGES TestCT, 3) CT
--1 0
UPDATE TestCT SET ID = 5 WHERE ID = 1
SELECT CHANGE_TRACKING_CURRENT_VERSION() AS current_version
--结果是5
SELECT * FROM CHANGETABLE(CHANGES TestCT, 4) CT
DELETE TestCT WHERE ID = 5
SELECT CHANGE_TRACKING_CURRENT_VERSION() AS current_version
--结果是6
SELECT * FROM CHANGETABLE(CHANGES TestCT, 5) CT
--6 NULL D NULL NULL 5
SELECT * FROM CHANGETABLE(VERSION TestCT, (ID), (4)) CT
--3 NULL 4
DECLARE @context AS varbinary(128);
SET @context = CAST('Test_Change_Tracking' AS varbinary(128));
WITH CHANGE_TRACKING_CONTEXT (@context)
UPDATE TestCT SET Description = 'NA';
-- The change now has an associated change context
SELECT CT.SYS_CHANGE_VERSION, CT.SYS_CHANGE_OPERATION,
CAST(SYS_CHANGE_CONTEXT AS varchar(20)) AS change_context
FROM CHANGETABLE(CHANGES TestCT, 6) AS CT
--7 U Test_Change_Tracking
--7 U Test_Change_Tracking
--7 U Test_Change_Tracking
SELECT CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('TestCT')) AS min_valid_version;
--结果0
TRUNCATE TABLE TestCT;
SELECT CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('TestCT')) AS min_valid_version;
--结果7
INSERT INTO TestCT VALUES (1, 'ABC', NULL)
SELECT * FROM CHANGETABLE(CHANGES TestCT, 0) CT
SELECT * FROM CHANGETABLE(CHANGES TestCT, 7) CT
ALTER TABLE TestCT ADD Age int;
go
UPDATE TestCT SET Age = 10;
SELECT CHANGE_TRACKING_IS_COLUMN_IN_MASK
(COLUMNPROPERTY(OBJECT_ID('TestCT'), 'Name', 'ColumnId'), SYS_CHANGE_COLUMNS)
AS is_column_Name_changed,
CHANGE_TRACKING_IS_COLUMN_IN_MASK
(COLUMNPROPERTY(OBJECT_ID('TestCT'), 'Description', 'ColumnId'), SYS_CHANGE_COLUMNS)
AS is_column_Description_changed,
CHANGE_TRACKING_IS_COLUMN_IN_MASK
(COLUMNPROPERTY(OBJECT_ID('TestCT'), 'Age', 'ColumnId'), SYS_CHANGE_COLUMNS)
AS is_column_Age_changed
FROM CHANGETABLE(CHANGES TestCT, 8) CT;
--结果是:0 0 1
SELECT CHANGE_TRACKING_CURRENT_VERSION() AS current_version
--结果是:9
ALTER TABLE TestCT DROP COLUMN Age
--结果是:9
SELECT CHANGE_TRACKING_CURRENT_VERSION() AS current_version