Obs*_*nix 7 sql-server sql-server-2008-r2 change-tracking change-data-capture
我正在考虑在我的系统中提供数据库级别的更改跟踪。我需要能够跟踪实体级别的更改,而不仅仅是单个表。
现在,我们在每个感兴趣的表上都有触发器,将表 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);
Run Code Online (Sandbox Code Playgroud)
在本例中,访问实体被认为是以下 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
Run Code Online (Sandbox Code Playgroud)
我需要知道这些实体之一何时发生了变化。如果我要更改 Employee 的电话号码,我需要能够看到它更改了 Visit 实体,以便我可以重新处理它。
现在,我的更改表记录了员工 ID。然后我运行一个查询,该查询将与该员工的所有访问作为 VisitorId。当您只查看两个表时,这听起来不错,但是当您将多个表(以及它们之间可能有多个抽象级别)考虑在内时,性能会变得非常缓慢。
我已经研究了更改数据捕获,但这似乎仍然是在表级别进行捕获。同样,我可以将 Modified date 列添加到所有表,并将视图中的所有修改组合起来以生成单个最大修改值 - 但考虑到我需要在该字段上进行过滤,我无法想象性能会那么好.
在 SQL Server 中是否有处理此问题的推荐方法?作为一个额外的考虑 - 虽然实例是 SQL 2008,但数据库仍处于 2000 兼容模式。
更新
我一直在研究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
Run Code Online (Sandbox Code Playgroud)
但这样做的缺点是需要连接每个表和一个关联的CHANGETABLE
对象,以便确定某些内容是否发生了变化。
我的计划是向每个源表添加一个行版本,并显示源表中的最大行版本。
这是假设 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
Run Code Online (Sandbox Code Playgroud)
显然,这只是为您提供了一个用于跟踪更改的标识符,您仍然需要创建一个表来跟踪它。