Change Tracking仅记录被修改行的主键、操作类型和版本号,不存旧值新值或时间戳;必须先启用数据库级再启用表级CT,表需有主键,查询须用CHANGETABLE(CHANGES)配合版本号,且需开启快照隔离。

Change Tracking 不会捕获“事件”本身,它只记录“哪些行被改了”,不存旧值、新值或时间戳。想靠它做审计日志或实时触发动作,直接踩坑。
必须先启用数据库和表的 Change Tracking
缺一不可,且顺序不能反:先数据库,再具体表。SQL Server 不会自动帮你级联开启。
-
ALTER DATABASE [YourDB] SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)—— 必须显式指定CHANGE_RETENTION,否则默认是 2 天,但很多同步任务周期长于这个值,会导致CHANGETABLE(CHANGES)返回空或报错 -
ALTER TABLE [dbo].[Orders] ENABLE CHANGE_TRACKING WITH (TRACK_COLUMNS_UPDATED = ON)——TRACK_COLUMNS_UPDATED = ON才能用CHANGE_TRACKING_IS_COLUMN_IN_MASK()判断哪几列被更新;关掉就只能知道“更新了”,不知道改了啥字段 - 表必须有主键,否则
ALTER TABLE ... ENABLE CHANGE_TRACKING直接报错:Msg 1986, Level 16, State 1, Line X: Tables that are enabled for change tracking must have a primary key.
查询变更要用 CHANGETABLE(CHANGES),不是轮询 or 触发器
它不是事件驱动模型,而是版本号驱动的拉取式查询。每次调用都得带一个 @last_sync_version,返回比它新的所有变更行主键 + 操作类型 + 版本号。
- 首次同步前,用
SELECT CHANGE_TRACKING_MIN_VALID_VERSION(OBJECT_ID('dbo.Orders'))获取合法起始版本,别硬写 0 或 1 —— 如果数据库刚启用 CT,这个最小有效版本可能远大于 0 - 每次成功获取变更后,立刻记下
SELECT CHANGE_TRACKING_CURRENT_VERSION()的结果,作为下次的@last_sync_version;丢失这个值 = 必须全量重刷 -
CHANGETABLE(CHANGES dbo.Orders, @last_sync_version)返回的sys_change_operation是单字符:I/U/D,不是字符串'INSERT';别在 WHERE 里写sys_change_operation = 'INSERT',会查不到
无法绕过快照隔离(SNAPSHOT ISOLATION)的隐性依赖
官方文档写的是 “recommended”,实际是事实上的刚需。不开启的话,CHANGETABLE 查询可能漏掉并发事务中已提交但尚未被 CT 系统标记的变更。
- 执行
ALTER DATABASE [YourDB] SET ALLOW_SNAPSHOT_ISOLATION ON和ALTER DATABASE [YourDB] SET READ_COMMITTED_SNAPSHOT ON - 不开这两个,尤其在高并发 DML 场景下,
CHANGETABLE(CHANGES)返回结果与实际数据状态不一致的概率显著升高 —— 这个问题不会报错,只会静默出错 - 注意:启用
READ_COMMITTED_SNAPSHOT会增大 tempdb 压力,上线前需压测
最易被忽略的一点:Change Tracking 的内部表不可见、不可索引、不可维护,它的性能和稳定性完全取决于你设的 CHANGE_RETENTION 和应用端同步频率的匹配度。一旦同步延迟超过保留期,CHANGE_TRACKING_MIN_VALID_VERSION() 就会跳变,而你的代码如果没做校验,就会直接崩在 CHANGETABLE 调用上。










