SQL Server 2008新特性――更改跟踪 (二)

2014-11-24 11:16:35 · 作者: · 浏览: 1
一个实例中建立TestDB1数据库并初始化t1表用于表示中心数据库。那么同步数据的操作应该是:

--首先将新增的数据插入到中心数据库中:
SET IDENTITY_INSERT TestDB1.dbo.t1 ON
INSERT INTO TestDB1.dbo.t1(c1,c2,c3,c4)
SELECT t1.*
FROM CHANGETABLE(CHANGES dbo.t1,0) AS ct
INNER JOIN t1
ON ct.c1=t1.c1
WHERE ct.SYS_CHANGE_OPERATION='I'

--接下来将更改的数据应用到中心数据库中:
UPDATE TestDB1.dbo.t1
SET c2=newt1.c2,c3=newt1.c3,c4=newt1.c4
FROM CHANGETABLE(CHANGES dbo.t1,0) AS ct
INNER JOIN dbo.t1 AS newt1
ON ct.c1=newt1.c1
WHERE ct.SYS_CHANGE_OPERATION='U' AND t1.c1=newt1.c1

--将删除的数据从中心数据库删除:
DELETE FROM TestDB1.dbo.t1
WHERE c1 IN (
SELECT c1
FROM CHANGETABLE(CHANGES dbo.t1,0) AS ct
WHERE ct.SYS_CHANGE_OPERATION='D')

这样我们就使用更改跟踪实现了数据库的同步。该同步操作时的版本号是3,这个版本号必须要单独记下来,那么下次再进行同步是就从3开始查询。

通过更改跟踪更新列

前面的同步脚本中关于数据update操作是:

UPDATE TestDB1.dbo.t1
SET c2=newt1.c2,c3=newt1.c3,c4=newt1.c4

由于c4是大对象数据类型,如果里面存放了几十兆或者更大的数据,而实际上我们更新的并不是c4列,那么这种更新方式必然很浪费时间和资源。前面我们对t1表已经启用了“跟踪已更新的列”,那么就可以根据实际更新的列来更新数据。

使用CHANGE_TRACKING_IS_COLUMN_IN_MASK()函数可以判断一个列是否发生了更改,如果发生了更改则返回1,没有更改则返回0。比如查询c2是否发生更改:

SELECT * ,CHANGE_TRACKING_IS_COLUMN_IN_MASK ( COLUMNPROPERTY( OBJECT_ID('dbo.t1'),'c2','ColumnId') , SYS_CHANGE_COLUMNS )
FROM CHANGETABLE(CHANGES dbo.t1,0) AS ct
WHERE ct.SYS_CHANGE_OPERATION='U'

这里返回0说明没有更改c2列,同样的方法可以判断出c3列发生了更改。

既然可以判断哪些列发生了更改,那么就可以根据发生更改的列来更新该列的数据,比如对于c2的更新语句就是:

UPDATE TestDB1.dbo.t1
SET c2=newt1.c2 --更新c2列
FROM CHANGETABLE(CHANGES dbo.t1,0) AS ct
INNER JOIN dbo.t1 AS newt1
ON ct.c1=newt1.c1
WHERE ct.SYS_CHANGE_OPERATION='U' AND t1.c1=newt1.c1
AND CHANGE_TRACKING_IS_COLUMN_IN_MASK(COLUMNPROPERTY(OBJECT_ID('dbo.t1'),'c2','ColumnId') , ct.SYS_CHANGE_COLUMNS )=1 --发生更改时才更新

同样的方法可以写出c3列、c4列的更新语句。如果觉得这样重复的写很麻烦,那么可以写一个存储过程,传入列名,检查该列是否更改,如果更改了则更新。

总结

更改跟踪是在偶尔连接的数据库应用和同步数据时非常有用的一个特性。更改跟踪里面的核心就是版本号,每次在同步数据时记录下当前的版本号,下次再同步时CHANGETABLE函数就传入上次同步的版本号,这样可以避免重复同步。

更改跟踪的跟踪记录数据是保存到系统表中的,由系统来维护,在开启数据库的更改跟踪时可以设置自动清除的时间,从而保证系统不会因为记录太多的跟踪数据而导致数据库文件大小急剧膨胀。

更改跟踪启用后对一般的DML操作(增删改)是不会有影响的,所有的DML SQL语句照常使用,而且启用更改跟踪后并不会对系统性能造成明细影响。

摘自:深蓝居