初探SQL Server 2008 Change Tracking
上一篇 / 下一篇 2008-03-31 09:47:01 / 个人分类:SQL Server 2008
前段时间评估了一下SQL Server 2008的CDC功能,总体发现CDC的开销还是不小的,特别是对日志文件的读。对于那些字段数量较多而且需要跟踪每个字段值更新的用户表,CDC的带来的额外开销则尤其明显。因此继续评估SQL Server 2008对数据更新跟踪的技术方案。
在SQL Server 2008的联机丛书中提到了,Change Tracking适用于单向或双向的数据同步应用场景。在接下来的一些列试用中,我们就能深刻体会到这一点。
激活Change Tracking
要使用Change Tracking,首先需要在数据库级别启用Change Tracking功能,我们可以通过两种途径启用Change Tracking。
- 使用T-SQL语句,例如要启用TestCT数据库的Change Tracking功能,可以通过提交如下语句ITPUB个人空间l)Z8T1U,i@6U?-\
ALTER DATABASE TestCTITPUB个人空间#t[#M L S+rC1a W
SET CHANGE_TRACKING = ONITPUB个人空间w$^2Q8GW,R-Oe
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON) - 在SQL Server Management Studio中通过设置数据库的属性,Change Tracking功能在数据库属性对话框中拥有一个独立的选项页。
其中我们会注意到CHANGE_RETENTION参数和AUTO_CLEANUP参数。因为Change Tracking所有的信息都会被添加到一张内部表中,所以这张内部表将会无限制地增长,如果我们不希望这张表的数据量一直增长,Change Tracking功能提供了一个后台的进程自动对内部表进行清理,清理的依据就是CHANGE_RETENTION,每次清理进程运行的时候都会将超过CHANGE_RETENTION参数中设定时间的记录删除掉,而清理进程是否会运行则依赖于AUTO_CLEANUP参数。CHANGE_RETENTION参数的时间单位可以是分钟、小时或天。
激活数据库级别的Change Tracking功能后,DBA就可以选择哪些需要更新跟踪的表了。我们同样也有两种方法在更新跟踪的表上启用Change Tracking功能:
- 使用T-SQL语句,例如要启用TestCT表上的更新跟踪,我们可以提交如下语句ITPUB个人空间 u
\4NO2IO&p
ALTER TABLE TestCT
;Dn#wy5Y2zh9a0ENABLE CHANGE_TRACKINGITPUB个人空间0tYjT;}'YN%\3y"l
WITH (TRACK_COLUMNS_UPDATED = ON) - 在SQL Server Management Studio中通过设置表的属性,Change Tracking功能在表属性对话框中拥有一个独立的选项页。
其中我们注意到有个参数是TRACK_COLUMN_UPDATED,当这个参数被设置为ON的时候,UPDATE语句提交后在内部表中将会记录UPDATE语句影响了哪些列,对于INSERT和DELETE语句,则所有列都是被影响到的。
使用Change Tracking
Change Tracking提供的信息可不像Change Data Capture那么详细,Change Data Capture可以提供每个事务影响到的数据的前像和后像。Change Tracking功能通过CHANGETABLE系统表来获得更新的版本信息。
CHANGETABLE有两种用法,一种是CHANGETABLE(CHANGES),一种是CHANGETABLE(VERSION)。前者用于返回某个sync_version后的数据变化情况,后者用于返回某行数据的最新的更改版本号。
CHANGETABLE(CHANGES)
这是一个表函数,语法结构为CHANGETABLE(CHANGEStable,last_sync_version),table参数为激活Change Tracking功能的表名,last_sync_version参数是希望获取更新的最小版本号。
table参数的值非常明白,我们希望获得哪张表的更新信息,就是这张表的名字了,而last_sync_version是影响返回结果集的主要因素。
+or-dX9\`4}E0举个例子,我们用下面这段脚本来详细说明Change Tracking记录下的信息:
CREATE TABLE TestCT
)W~)Rn^/Il`
@L,iw"]0(
}'nv$eT*j"na0 ID int PRIMARY KEY,
bve
C+qZr0 Name varchar(50),ITPUB个人空间
E)f*Q$qU@M
Description varchar(200)
|S`$_ cV0yq9H0)
#d{h8CNy.V&w;@0GO
2t [y.r6}$@{!V0ALTER TABLE TestCT
,H;Sm'v9R`0ENABLE CHANGE_TRACKING
#@6\8ON*H0WITH (TRACK_COLUMNS_UPDATED = ON)ITPUB个人空间6U2D'Ii$P+k0{*`L
GO
这个时候TestCT表的Change Tracking功能就被激活了,这张表上所有的数据更新都会被记录到一张内部表中,接着我们就可以在TestCT表上提交各种DML语句了。ITPUB个人空间]O,} ?0X,mz$bS M[
INSERT INTO TestCT VALUES (1, 'ABC', NULL)
这个时候我们可以通过CHANGETABLE函数来查看TestCT的更新历史ITPUB个人空间1mz:a"?0I$e
SELECT * FROM CHANGETABLE(CHANGES TestCT, 0) CT
9iy
`,@#Q?0返回结果为ITPUB个人空间,Y},rvrJ9sJ
| SYS_CHANGE -i)q(y:k|^q;s1cj0_VERSION | SYS_CHANGE )KY P} C[\&s#c0_CREATION_VERSION | SYS_CHANGEITPUB个人空间KR}T*UUO2x;fv _OPERATION | SYS_CHANGE #} SC4QqB0C$m2O0_COLUMNS | SYS_CHANGEITPUB个人空间$EF;v;C!? c0f _CONTEXT | ID |
| 1 | 1 | I | NULL | NULL | 1 |
返回结果集中:
- SYS_CHANGE_VERSION是一个bigint的字段,表示的当前这行数据最新的更新版本号。
- SYS_CHANGE_CREATION_VERSION代表的是当前数据行被插入数据表的更新版本号。
- SYS_CHANGE_OPERATION是一个nchar(1)的字段,I代表Insert,U代表Update,D代表Delete。
- SYS_CHANGE_COLUMNS代表更新操作影响到了哪些数据列,这个字段的结果是个varbinary(4100)。这个字段只有在表上激活Change Tracking时将TRACK_COLUMN_UPDATED选项设置为ON时才会返回有效值,并且对于INSERT和DELETE操作返回的都是NULL,因为DELETE和INSERT其实影响到了所有数据列,只有UPDATE操作才会返回值,这个字段的值可以通过CHANGE_TRACKING_IS_COLUMN_IN_MASK()函数来解析。
- SYS_CHANGE_CONTEXT是一个varbinary(128)的字段,这个字段可以记录数据更新的上下文环境信息,不过上下文环境信息需要在提交DML语句时显式地通过WITH CHANGE_TRACK_CONTEXT语句提供。
- ID是TestCT表的主键字段,因此如果TestCT的主键是内容为(ID, Name)的组合主键,则除了ID外,CHANGETABLE返回结果集中还会多一个Name字段。
我们接着测试,
}dai,`B
@tb0|p0UPDATE TestCT SET Name = 'abc' WHERE ID = 1
提交完这句语句后,其实TestCT表已经有了两次更新,一次是INSERT操作,一次是UPDATE操作,但是这两次操作都是针对ID为1的这一行数据,这个时候我们在CHANGETABLE函数中通过不同的last_sync_version参数会得到不同的返回结果。
SELECT * FROM CHANGETABLE(CHANGES TestCT, 0) CT
t1V8DXk4^0返回结果为
'X.R/Zs0`%r5z0
| SYS_CHANGEITPUB个人空间Z*GW*U~0t _VERSION | SYS_CHANGEITPUB个人空间 wbh
~ }O _CREATION_VERSION | SYS_CHANGEITPUB个人空间J`_)qZI _OPERATION | SYS_CHANGE UHDVph0_COLUMNS | SYS_CHANGEITPUB个人空间sq U!eT _CONTEXT | ID |
| 2 | 1 | I | NULL | NULL | 1 |
从返回结果看,主键值为1的这行数据最近的更新版本为2,而插入表时的更新版本为1,代表这行数据在插入数据表后已经有过更新,但是SYS_CHANGE_OPERATION仍然是I。原因是我们选取的last_sync_version参数值是0,代表我们上次同步时数据更新版本是0,而这行数据是在版本0后被插入表的,因此这行数据还没有出现在同步的目的表中,因此在我们进行同步时首先要处理INSERT操作,而被INSERT到源表中的原始记录已经被更新了(在版本2时),因此我们只能将INSERT操作和UPDATE操作进行合并,直接取得UPDATE后的数据行写入目的表。
但是如果我们提交的语句是
5@:R|4|m/S0SELECT * FROM CHANGETABLE(CHANGES TestCT, 1) CT
$V&G W3Z,FnXC#c9^0返回结果则会变为ITPUB个人空间 b5`
T2Z7{1_9@*\_0z
| SYS_CHANGEITPUB个人空间"YW-gY#S;qD _VERSION | SYS_CHANGEITPUB个人空间'_
Qu(VJ8M S*C8v _CREATION_VERSION | SYS_CHANGE |