sql-server – 跨多个表更改跟踪

我正在考虑在我的系统中提供数据库级别更改跟踪.我需要能够跟踪实体级别的更改,而不仅仅是单个表.

现在,我们在每个感兴趣的表上都有触发器,将表PK写入Change_Event表.然后我们可以查询该表,并将其归结为代表整个实体的PK.然后,我们可以检索该实体的数据并对其执行相关操作.

作为示例,请考虑以下(简化)示例:

CREATE TABLE Employee
(
    Id INT IDENTITY PRIMARY KEY,
    Name VARCHAR(250) NOT NULL,
    Telephone VARCHAR(15) NOT Null
);

CREATE Table Visit
(
    Id INT IDENTITY PRIMARY KEY,
    VisitDate DATETIME2 Not NULL,
    [Address] VARCHAR(500) NOT NULL,
    VisitorId INT NOT NULL,
    CONSTRAINT FK_Visit_VisitorId FOREIGN KEY (VisitorId) REFERENCES Employee (Id)
);

INSERT into Employee (Name, Telephone)
VALUES ('John Doe', '123456789'),
('Jane Smith', '999555333');

INSERT INTO Visit (VisitDate, Address, VisitorId)
VALUES (SYSDATETIME(), '123 Fake St', 1),
(GETDATE() + 5, '99 Test Av', 2);

在此示例中,访问实体被视为以下xml:

SELECT Id,
       CAST((
           SELECT Id,
                  VisitDate,
                  Address,
                  (
                      SELECT E.Id,
                             E.Name,
                             E.Telephone
                      FROM Employee E
                      WHERE E.Id = V.VisitorId
                      FOR XML RAW ('Visitor'), TYPE, ELEMENTS
                  )
                  Visitor
           FROM Visit V
           WHERE V.Id = Visit.Id
           FOR XML RAW ('Visit'), ELEMENTS
       ) AS XML) AS Data
FROM Visit

当其中一个实体发生变化时,我需要能够知道.如果我要更改Employee的电话号码,我需要能够看到已经更改了Visit实体,以便我可以重新处理它.

现在,我的更改表记录了员工ID.然后,我运行一个查询,向我提供与该员工的所有访问作为VisitorId.当你只看两个表时,这听起来不错,但是当你考虑几个表(并且它们之间可能有几个抽象层)时,性能会变得非常慢.

我已经研究过Change Data Capture,但这似乎仍然是在表级捕获.同样,我可以将修改日期列添加到所有表中,并组合视图中的所有修改后的值以产生单个最大修改值 – 但考虑到我需要对该字段进行过滤,我无法想象性能会如此之好.

是否有推荐的方法在SQL Server中处理此问题?作为一个额外的考虑因素 – 虽然Instance是SQL 2008,但DB仍处于2000兼容模式.

UPDATE

我一直在研究Change Tracking,它在桌面级别上工作得很好.不幸的是,它与上面的选择不太合作.

我甚至尝试基于该选择创建模式绑定视图,并在视图上启用更改跟踪,但这似乎是一个不能应用于视图的选项.

我可以使用类似下面的内容使其工作:

WITH ChangedVisits AS
(
    SELECT DISTINCT OV.Id
    FROM dbo.Visit OV
        INNER JOIN Employee E ON OV.VisitorId = E.Id
        LEFT JOIN CHANGETABLE(CHANGES Visit, @LastSyncVersion) AS VCT ON OV.Id = VCT.Id
        LEFT JOIN CHANGETABLE(CHANGES Employee, @LastSyncVersion) AS ECT ON OV.VisitorId = ECT.Id
    WHERE VCT.Id IS NOT NULL
        OR ECT.Id IS NOT NULL
)
SELECT Id,
       CAST(
       (
           SELECT V.Id as [@Id],
                  V.VisitDate,
                  Address,
                  (
                      SELECT E.Id,
                             E.Name,
                             E.Telephone
                      FROM dbo.Employee E
                      WHERE E.Id = V.VisitorId
                      FOR XML PATH(''), TYPE, ELEMENTS
                  )
                  Visitor
           FROM dbo.Visit V
           WHERE V.Id = CV.Id
           FOR XML PATH ('Visit'), ELEMENTS
       )
       AS XML) AS Data
FROM ChangedVisits CV

但缺点是需要连接每个表和一个相关的CHANGETABLE对象,以便在事情发生变化时进行计算.

最佳答案
我的计划是为每个源表添加一个rowversion,并显示源表中的最大rowversion.

这假设rowversion在整个数据库中是唯一的,并且在每个表中都没有增加(我需要检查该假设是否正确).

SELECT 
 ft.[col1]
,ft.[col2]
,ft.[col3]
,ft.[col4]
,dt.dim_id
,dt.name
, (SELECT MAX(rv) 
   FROM (VALUES (ft.row_ver), (dt.row_ver)) AS value(rv)) AS max_row_ver
FROM [dbo].[myFirstTable] ft
INNER JOIN [dbo].[dim_table1] dt ON ft.[col5_fk] = dt.dim_id

显然,这只会为您提供用于跟踪更改的标识符,您仍然需要创建一个表来跟踪它.

转载注明原文:sql-server – 跨多个表更改跟踪 - 代码日志