SQL 更改跟踪不跟踪多记录更新

dyl*_*anT 6 sql-server change-tracking sql-server-2014

我在一个大约有 300 万行的表上打开了 SQL Server 更改跟踪。

开启变更追踪:

ALTER DATABASE FooDB
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 10 DAYS, AUTO_CLEANUP = OFF)

ALTER TABLE [dbo].[fooTable]
ENABLE CHANGE_TRACKING
WITH (TRACK_COLUMNS_UPDATED = OFF)
Run Code Online (Sandbox Code Playgroud)

如果我单独编辑行,一切都很好,每个插入/更新/删除都会存储一个更改。

如果我运行更新多行的更新查询,我只会在更新中获得第二行的更改记录。

所以:

UPDATE fooTable SET name = UPPER(name) where id between 100 and 200
Run Code Online (Sandbox Code Playgroud)

其次是(以确保对每一行进行实际更新)

UPDATE fooTable SET name = LOWER(name) where id between 100 and 200
Run Code Online (Sandbox Code Playgroud)

仅生成记录 101 的更改记录。

SQL Express 2014

dyl*_*anT 3

我已经弄清楚发生了什么事。

我做出的错误假设是,如果更改导致同时更新 4 行,则会导致表的 SYS_CHANGE_VERSION 增加 4。但事实并非如此。尽管changetable中有四次更改,但版本仅上升1(这是一次更改更改了多条记录。)

任何有兴趣亲自测试它的人都可以使用下面的代码。

-- 1. Create Table
CREATE TABLE dbo.fooTable(
    [ID] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
    [Title] [nvarchar](20) NULL,
    [Surname] [nvarchar](128) NULL,
    [MiddleNames] [nvarchar](128) NULL,
    [Firstname] [nvarchar](128) NULL,
    [CreateDate] [datetime2](7) NOT NULL CONSTRAINT         [DF_CustomerProfile_CreateDate_I]  DEFAULT (getdate()),
    [LastModifiedDate] [datetime2](7) NOT NULL CONSTRAINT     [DF_CustomerProfile_LastModifiedDate_I]  DEFAULT (getdate()),
 CONSTRAINT [PK_fooTable_I] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,     ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)

GO

-- 2. Insert dummy data
insert into fooTable (Title, Firstname, MiddleNames, Surname, CreateDate,     lastModifiedDate)
values ('Mr','John',null,'Smith',GetDate()-5, getdate())
insert into fooTable (Title, Firstname, MiddleNames, Surname, CreateDate,     lastModifiedDate)
values ('Mrs','Mary','Beth','Jones',GetDate()-5, getdate())
insert into fooTable (Title, Firstname, MiddleNames, Surname, CreateDate,     lastModifiedDate)
values ('Ms','Thanh',null,'Nguyen',GetDate()-5, getdate())
insert into fooTable (Title, Firstname, MiddleNames, Surname, CreateDate,     lastModifiedDate)
values ('Dr','Lee','Evan','Oscars',GetDate()-5, getdate())

-- 3. Turn on Change Tracking
-- Database
ALTER DATABASE fooDB
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 10 DAYS, AUTO_CLEANUP = OFF)

-- Tables
ALTER TABLE dbo.fooTable
ENABLE CHANGE_TRACKING
WITH (TRACK_COLUMNS_UPDATED = OFF)

-- 4. Check current version
Select CHANGE_TRACKING_CURRENT_VERSION() -- Should be Zero if you have never     turned change tracking on before.

-- 5. Make a single change
Update fooTable set MiddleNames = 'Arthur' where Surname = 'Smith'

-- 6. Check current version, should have gone up by 1
Select CHANGE_TRACKING_CURRENT_VERSION() -- Should be 1 if you have never turned change tracking on before.

-- 7. See the change, should be Type U on record with ID 1 
DECLARE @version bigint
SET @version = CHANGE_TRACKING_CURRENT_VERSION()-1
Select CT.*
    FROM CHANGETABLE(CHANGES dbo.fooTable, @version) CT

-- 8. If everything is OK up to here, that's great. Now we have a problem.
-- Update all the rows in the table
Update fooTable set lastModifiedDate = Getdate() + 5

-- 9. Check current version, I expected it would go up by 4, one update for each record
Select CHANGE_TRACKING_CURRENT_VERSION() -- Should be 5 if you have never turned change tracking on before.

-- 10. View all changes for the table. There should be 4 (the first one will be gone now.)
Select CT.*
    FROM CHANGETABLE(CHANGES dbo.fooTable, 0) CT

-- Observe that each row has the same SYS_CHANGE_VERSION which means I need to deal with it and move on.
Run Code Online (Sandbox Code Playgroud)