【问题标题】:Trying to understand some SQL Server change tracking features试图了解一些 SQL Server 更改跟踪功能
【发布时间】:2018-09-07 14:24:31
【问题描述】:

我正在开发具有更改跟踪功能的 SQL Server 2016 SP1,我有一个问题要问您。

我有一个启用了更改跟踪的数据库。该数据库包含一个表Table,它激活了“更改跟踪”,但没有“跟踪更新的列”选项。

例如,在Table 上,我只有一个名为Id 的列,类型为“uniqueidentifier”,这是我的PK。

在开始时,我的更改跟踪当前版本是 0。

我得到了它:

SELECT CHANGE_TRACKING_CURRENT_VERSION();

我在Table 中添加了一个新行:

INSERT INTO dbo.[Table] (Id) 
VALUES ('C99F9E2A-1974-47CE-A406-481076F53BBD');

现在,我的更改跟踪当前版本现在是 1。

通过这个请求,我可以在更改跟踪系统中看到我的元素:

SELECT * 
FROM CHANGETABLE (CHANGES dbo.[Table], 0) CT;

结果是:

现在,我用这个删除我的行:

DELETE FROM dbo.[Table] 
WHERE Id = 'C99F9E2A-1974-47CE-A406-481076F53BBD';

更改跟踪当前版本现在是 2。

我用与之前相同的请求再次插入它。

更改跟踪当前版本现在是 3。

有了这个请求,我得到了这个结果:

SELECT * 
FROM CHANGETABLE (CHANGES dbo.[Table], 1) CT;

现在是我的问题,为什么我在 SYS_CHANGE_OPERATION 中得到“U”?

为什么不是“我”导致 1

感谢您的帮助!

【问题讨论】:

    标签: sql-server change-tracking


    【解决方案1】:

    添加一些动机,更改跟踪功能的目的是使您能够查看自上次检查以来发生的更改,使您能够收集这些更改并将其应用到其他表或外部系统。

    如果您查看自就在删除之后发生的更改,您将看到操作为I。但是,如果您查看自删除之前以来的更改,您会“跳过”删除。但是更改跟踪不记得删除之前的非键值是什么。因此该行报告为已更新。

    EG

    ALTER DATABASE current  
    SET CHANGE_TRACKING = ON  
    (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON)  
    go
    drop table if exists ct
    
    create table ct(id uniqueidentifier primary key)
    
    ALTER TABLE ct
    ENABLE CHANGE_TRACKING  
    WITH (TRACK_COLUMNS_UPDATED = ON) 
    
    declare @beforeInsert bigint = (SELECT CHANGE_TRACKING_CURRENT_VERSION());
    INSERT INTO dbo.ct (Id) VALUES ('C99F9E2A-1974-47CE-A406-481076F53BBD');
    declare @afterInsert bigint = (SELECT CHANGE_TRACKING_CURRENT_VERSION());
    DELETE FROM dbo.ct WHERE Id = 'C99F9E2A-1974-47CE-A406-481076F53BBD';
    declare @afterDelete bigint = (SELECT CHANGE_TRACKING_CURRENT_VERSION());
    INSERT INTO dbo.ct (Id) VALUES ('C99F9E2A-1974-47CE-A406-481076F53BBD');
    
    
    SELECT 'from before insert to current',id, sys_change_operation FROM CHANGETABLE (CHANGES dbo.ct, @beforeInsert) CT
    union all
    SELECT 'from after insert to current',id, sys_change_operation FROM CHANGETABLE (CHANGES dbo.ct, @afterInsert) CT
    union all
    SELECT 'from after delete to current',id, sys_change_operation FROM CHANGETABLE (CHANGES dbo.ct, @afterDelete) CT
    

    输出

                                  id                                   sys_change_operation
    ----------------------------- ------------------------------------ --------------------
    from before insert to current C99F9E2A-1974-47CE-A406-481076F53BBD I
    from after insert to current  C99F9E2A-1974-47CE-A406-481076F53BBD U
    from after delete to current  C99F9E2A-1974-47CE-A406-481076F53BBD I
    

    【讨论】:

    • 哦,当然,提供一个很好的例子:-)。
    【解决方案2】:

    来自Microsoft Docs CHANGETABLE

    如果您删除一行,然后插入具有旧主键的行,则更改将被视为对该行中所有列的更新。

    据推测,id 是相关表的主键。

    另外,不要使用id作为列名,使用TableID...所以如果表名是Users,那么主键(如果使用代理键)应该是@ 987654327@。使用id 作为主键列的名称会造成相当大的混乱,并使您的代码容易出错。详情请查看this 答案。

    【讨论】:

    • 这正是我的想法。尽管我不确定我是否完全同意您回答的最后一段。我不介意PK的名字ID和FK的名字UserId
    • FWIW,我经常看到 Id 涉及 ORM,因为它使 OO 代码能够与实体一起工作。
    • 另外Id 可以更好地建模子类型。所以你不会像 Adventureworks 那样 Sales.SalesPerson 的 PK 为 BusinessEntityId
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多