对于跟踪数据库表的 DML 操作,SQLserver 2008 及以上版本提供了 变更数据捕获和更改跟踪。
变更数据库捕获 与 跟踪更改 的区别:
?
变更数据捕获与更改跟踪都是记录表的DML操作
变更数据捕获可把操作数据的历史值保存下来;更改跟踪捕获更改了表行这一事实,但不会捕获更改的数据。
变更数据捕获使用异步进程捕获,该进程扫描事务日志;更改跟踪同步跟踪DML操作
变更数据捕获存储在当前数据库system表中,更改表可指定存储位置;更改跟踪表存储在系统架构sys中,不可查看结构定义
更多参考:比较变更数据捕获和更改跟踪
【接下来测试】
?
创建测试表:
?
USE [MyDatabase]
GO
CREATE TABLE [dbo].[TestTab](
[id] [int] NOT NULL,
[name] [varchar](50) NOT NULL,
[insertDate] [datetime] NOT NULL,
[value] [numeric](14, 4) NULL,
[info] [varchar](20) NULL,
CONSTRAINT [PK_TestTab] PRIMARY KEY CLUSTERED ([id] ASC)ON [PRIMARY]
) ON [PRIMARY]
GO
启用数据库更改跟踪:(参考:ALTER DATABASE SET 选项 (Transact-SQL))
?
?
USE [master]
GO
ALTER DATABASE [MyDatabase] SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS,AUTO_CLEANUP = ON)
GO
?

?
启用表的更改跟踪:(参考:ALTER TABLE (Transact-SQL))
?
USE [MyDatabase]
GO
ALTER TABLE [dbo].[TestTab] ENABLE CHANGE_TRACKING WITH(TRACK_COLUMNS_UPDATED = ON)
GO
?
查看数据库或表启用情况:(参考:sys.change_tracking_databases,sys.change_tracking_tables)
?
SELECT DB_NAME(database_id) DBName,retention_period,retention_period_units_desc,is_auto_cleanup_on
FROM sys.change_tracking_databases
SELECT OBJECT_NAME(object_id) TableName,is_track_columns_updated_on
FROM sys.change_tracking_tables
?
那跟踪表的数据存储在哪呢?使用内部表可查看
?
-- 每个启用跟踪的表保存一行
SELECT * FROM sys.internal_tables WHERE internal_type_desc='CHANGE_TRACKING'
SELECT * FROM sys.sysobjects WHERE id = (
SELECT object_id FROM sys.internal_tables
WHERE internal_type_desc='CHANGE_TRACKING'
AND parent_object_id=object_id('TestTab')
)
-- 查看表大小
exec sp_spaceused 'sys.change_tracking_37575172'
exec sp_spaceused 'sys.syscommittab'
?
插入测试数据:
?
-- 插入测试数据
insert into [dbo].[TestTab](id,name,insertDate,value,info)
select 1,'kk',GETDATE(),10,'info'
union all
select 2,'GG',GETDATE(),50,''
union all
select 3,'MM',GETDATE(),0,null
怎么查看跟踪信息,系统提供了一个表值函数 CHANGETABLE :
?
?
-- 返回<版本号>之后的所有行更改信息(如:查看版本号为0及之后的所有更改信息)
-- SELECT * FROM CHANGETABLE(CHANGES <表名>,<版本号>) as T
SELECT * FROM CHANGETABLE(CHANGES dbo.TestTab,0) as T
-- 返回指定行的最新更改跟踪信息(如: id=3 最新更改情况)
-- SELECT * FROM CHANGETABLE(VERSION <表名>,(<主键列>),(<主键值>)) as T
SELECT * FROM CHANGETABLE(VERSION dbo.TestTab,(id),(3)) as T
?
?
CHANGETABLE CHANGES:
| 列名 |
数据类型 |
说明 |
| SYS_CHANGE_VERSION |
bigint |
与上次对行的更改关联的版本值。(同一批次操作,版本号相同) |
| SYS_CHANGE_CREATION_VERSION |
bigint |
与上次插入操作关联的版本值。(同一批次操作,版本号相同) |
| SYS_CHANGE_OPERATION |
nchar(1) |
指定更改的类型: U = 更新 I = 插入 D = 删除 |
| SYS_CHANGE_COLUMNS |
varbinary(4100) |
列出自基准版本以后发生了更改的列。 [注意] 计算列永远不会作为更改的列列出。 以下任何一个条件为真时,值为 NULL: *未启用列更改跟踪。 *操作是插入操作或删除操作。 *在一个操作中更新了所有非主键列。不应直接解释此二进制值。 |
| SYS_CHANGE_CONTEXT |
varbinary(128) |
更改可以在 INSERT、UPDATE 或 DELETE 语句中使用 WITH 子句选择指定的上下文信息。 |
| <<主键列值>> |
与用户表列相同 |
被跟踪表的主键值。这些值在用户表中唯一标识各行。(与当前表连接反应最新数据) |
?
CHANGETABLE VERSION :
?
| 列名 |
数据类型 |
说明 |
| SYS_CHANGE_VERSION |
bigint |
与行关联的当前更改版本值。 如果在超过更改跟踪保留期的时段内没有进行更改,或者在启用更改跟踪之后未更改行,则值为 NULL。 |
| SYS_CHANGE_CONTEXT |
varbinary(128) |
更改可以在 INSERT、UPDATE 或 DELETE 语句中使用 WITH 子句选择指定的上下文信息。 |
| <<主键列值>> |
与用户表列相同 |
被跟踪表的主键值。这些值在用户表中唯一标识各行。(与当前表连接反应最新数据) |
?
更改数据:
?
update [dbo].[TestTab] set insertDate = GETDATE(),info = 'update' where id=3
update [dbo].[TestTab] set insertDate = GETDATE(),value = 100 where id=3 --执行了2次
检查版本号信息:(参考: