分类: 数据库开发技术
2010-05-01 11:22:45
数据变更需要与一个基线做对比。当你首先将你的客户端(一个NET应用程序和/或另一个SQL Server表)与HumanResources.Department表同步时,你从这个表的所有记录获得一个原始的数据集。你还获得基线版本数字,例如这时所有记录的最大版本数字,并将它记录下来用于下一次同步。下一次同步时,系统确定哪些记录从这个基线版本以来进行了修改,而一个新的基线版本被保存下来用于下次的同步。这个算法如下所示。
-- Obtain the current synchronization version. This will be used the next time CHANGETABLE(CHANGES...) is called. SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION(); -- If this is the first synchronization session IF (@sync_initialized = 0) BEGIN -- Initialize from the table SELECT DepartmentID, Name, GroupName, ModifiedDate FROM HumanResources.Department END ELSE BEGIN -- Obtain incremental changes by using the synchronization version obtained the last time the data was synchronized. SELECT CT.SYS_CHANGE_OPERATION, DepartmentID, Name, GroupName, ModifiedDate FROM HumanResources.Department RIGHT OUTER JOIN CHANGETABLE(CHANGES HumanResources.Department, @last_synchronization_version) AS CT ON P.DepartmentID = CT.DepartmentID END |
DECLARE @synchronization_version bigint -- Obtain the current synchronization version. This will be used the next time CHANGETABLE(CHANGES...) is called. SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION() SELECT @synchronization_version -- Initialize from the base table SELECT DepartmentID, Name, GroupName, ModifiedDate FROM HumanResources.Department |
让我们插入一条新的记录到这个表中并更新一条已有的记录。
INSERT INTO HumanResources.Department
(Name, GroupName, ModifiedDate)
VALUES ('Product Design', 'Research and Development', GETDATE())
UPDATE HumanResources.Department
SET GroupName='Accounting'
WHERE DepartmentID=10
要获得上次版本0以来的变更,运行下面的脚本。
DECLARE @synchronization_version bigint -- Obtain the current synchronization version. This will be used the next time CHANGETABLE(CHANGES...) is called. SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION() SELECT @synchronization_version -- Obtain incremental changes by using the synchronization version obtained the last time the data was synchronized. SELECT CT.SYS_CHANGE_VERSION, CT.SYS_CHANGE_OPERATION, CT.DepartmentID, Name, GroupName, ModifiedDate FROM HumanResources.Department D RIGHT OUTER JOIN CHANGETABLE(CHANGES HumanResources.Department, 0) AS CT ON D.DepartmentID = CT.DepartmentID |
如果你在表HumanResources.Department 上激活了字段跟踪,那么你可以只从变更了的字段获取数据。
DECLARE @synchronization_version bigint -- Obtain the current synchronization version. This will be used the next time CHANGETABLE(CHANGES...) is called. SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION() SELECT @synchronization_version -- Obtain incremental changes by using the synchronization version obtained the last time the data was synchronized. SELECT CT.SYS_CHANGE_VERSION, CT.SYS_CHANGE_OPERATION, CT.DepartmentID, CASE CHANGE_TRACKING_IS_COLUMN_IN_MASK (COLUMNPROPERTY(OBJECT_ID('HumanResources.Department'), 'Name', 'ColumnId'), SYS_CHANGE_COLUMNS) WHEN 1 THEN Name ELSE NULL END as Name, CASE CHANGE_TRACKING_IS_COLUMN_IN_MASK(COLUMNPROPERTY (OBJECT_ID('HumanResources.Department'), 'GroupName', 'ColumnId'), SYS_CHANGE_COLUMNS) WHEN 1 THEN GroupName ELSE NULL END AS GroupName, ModifiedDate FROM HumanResources.Department D RIGHT OUTER JOIN CHANGETABLE(CHANGES HumanResources.Department, 0) AS CT ON D.DepartmentID = CT.DepartmentID |
让我们删除新添加的记录。
DELETE FROM HumanResources.Department WHERE DepartmentID=17 要获得从上次版本2以来的变更,运行之前的脚本,使用新版本2。 DECLARE @synchronization_version bigint -- Obtain the current synchronization version. This will be used the next time CHANGETABLE(CHANGES...) is called. SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION() SELECT @synchronization_version -- Obtain incremental changes by using the synchronization version obtained the last time the data was synchronized. SELECT CT.SYS_CHANGE_VERSION, CT.SYS_CHANGE_OPERATION, CT.DepartmentID, Name, GroupName, ModifiedDate FROM HumanResources.Department D RIGHT OUTER JOIN CHANGETABLE(CHANGES HumanResources.Department, 2) AS CT ON D.DepartmentID = CT.DepartmentID |
因为如果AUTO_CLEANUP选项设置为打开,那么变更跟踪信息可以在下次同步运行之前被删除,我们还需要将@last_synchronization_version和用于特定表的变更跟踪表中保存的最小版本相比较。如果@last_synchronization_version小于CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('HumanResources.Department')),那么我们需要重新初始化并获得一个包含HumanResources.Department base表所有记录的新基线。因此,这个条件
IF (@sync_initialized = 0)
需要改为
IF (@last_synchronization_version 在一个繁忙的系统上,在获得当前版本和从CHANGETABLE()函数获得变更之间,表HumanResources.Department 有可能被其它会话改变,或变更跟踪信息可能被清理进程删除了并启动CHANGE_TRACKING_MIN_VALID_VERSION来添加。因此,最好使用快照隔离来确保在事务过程中所有的变更跟踪信息是一致的。完整的算法如下所示。 总结 本篇文章介绍了怎样使用CHANGETABLE函数来获取数据变更。展示了两个算法。你可以在你的.NET应用程序中使用Sync Services来执行这两个算法。
在数据库上激活快照隔离会对数据库增加不小的性能成本。如果你倾向于不使用快照隔离,那么一个获得变更的替代算法如下所示。
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRAN
DECLARE @synchronization_version bigint
-- Obtain the current synchronization version. This will be used the next time CHANGETABLE(CHANGES...) is called.
SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION()
SELECT @synchronization_version
IF (@last_synchronization_version < CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('HumanResources.Department')))
BEGIN
-- Initialize from the base table
SELECT DepartmentID, Name, GroupName, ModifiedDate
FROM HumanResources.Department
END
ELSE
BEGIN
-- Obtain incremental changes by using the synchronization version obtained the last time the data was synchronized.
SELECT CT.SYS_CHANGE_OPERATION, CT.DepartmentID, Name, GroupName, ModifiedDate
FROM HumanResources.Department D
RIGHT OUTER JOIN
CHANGETABLE(CHANGES HumanResources.Department, @last_synchronization_version) AS CT
ON
D.DepartmentID = CT.DepartmentID
END
COMMIT TRAN
这个算法不使用快照隔离,它使用新版本来确保这个新版本从CHANGETABLE(CHANGES …)函数返回之后没有变更。但是,当CHANGE_TRACKING_MIN_VALID_VERSION改变而@last_synchronization_version变得无效时,这个算法就不能解决这个问题。
DECLARE @synchronization_version bigint
SET @synchronization_version = CHANGE_TRACKING_CURRENT_VERSION()
SELECT @synchronization_version
IF (@last_synchronization_version < CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('HumanResources.Department')))
-- Initialize from the base table
SELECT DepartmentID, Name, GroupName, ModifiedDate
FROM HumanResources.Department
ELSE
BEGIN
-- Obtain incremental changes by using the synchronization version obtained the last time the data was synchronized.
SELECT CT.SYS_CHANGE_OPERATION, CT.DepartmentID, Name, GroupName, ModifiedDate
FROM HumanResources.Department D
RIGHT OUTER JOIN
CHANGETABLE(CHANGES HumanResources.Department, @last_synchronization_version) AS CT
ON
D.DepartmentID = CT.DepartmentID
WHERE (CT.SYS_CHANGE_CREATION_VERSION <= @synchronization_version)
END