我有一个审计跟踪解决方案,它将INSERTED或DELETED表的内容转储到XML的触发器中,以及当前用户,时间戳等。对于插入和更新,它记录前者,并删除它记录后者。
但是,为了确定同一记录的两个日志之间的变化,我需要在审计表上自行加入以获取先前的记录。这本身并不会太糟糕,但如果我可以在触发器中记录data_from和data_to,性能会大大提高。
显而易见的解决方案是在INSERTED和DELETED之间使用内部联接进行更新,但问题是这些表不能并且不能被索引,因此数据库需要执行完整的逐行哈希为了产生结果。因为在更新触发器中,INSERTED和DELETED记录中的顺序是相同的,所以我不禁感到必须有某种方式可以在不使用连接和不使用游标的情况下水平组合这两个表。
我已经尝试过的以及我所知道的内容不起作用:
有什么想法吗?
答案 0 :(得分:3)
您是否考虑过使用Change Data Capture功能?它比触发器更有效地捕获更改,它是一个异步后台进程,这意味着对实际进行更新的进程影响最小。
答案 1 :(得分:2)
我最终采用的解决方案是将inserted
和deleted
表中的数据传输到索引表变量中,然后从那里使用它们。性能不如CDC那么好,但是可接受且线性,并且上市时间要短得多。我编写了一个代码生成器来生成触发器,我在下面包含了一个示例:
IF TRIGGER_NESTLEVEL(OBJECT_ID('TR_su_type_code_audit_log')) > 1 RETURN
DECLARE @user_key INT, @tp INT = 0
IF EXISTS(SELECT 1 FROM deleted) SET @tp += 1
IF EXISTS(SELECT 1 FROM inserted) SET @tp += 2
DECLARE @i TABLE (type_code_key int, audit_data VARCHAR(MAX), PRIMARY KEY (type_code_key))
DECLARE @d TABLE (type_code_key int, audit_data VARCHAR(MAX), PRIMARY KEY (type_code_key))
INSERT INTO @i SELECT type_code_key,
(SELECT type_code_key, type_code_group, id, description, is_system_reserved, site_key, code_int,
code_str, image_index, image_filename FOR XML RAW('audit'))
FROM inserted
INSERT INTO @d SELECT type_code_key,
(SELECT type_code_key, type_code_group, id, description, is_system_reserved, site_key, code_int,
code_str, image_index, image_filename FOR XML RAW('audit'))
FROM deleted
SET @user_key = dbo.f_get_current_user()
IF @tp = 2
BEGIN
INSERT INTO audit_trail (mod_type, mod_date, user_key, audit_rec_table, audit_rec_key, audit_rec_key_1,
audit_rec_key_2, is_delta, data_to)
SELECT 'I', GETDATE(), @user_key, 'su_type_code', t.type_code_key, NULL, NULL, 0, audit_data
FROM @i t
END ELSE IF @tp = 1
BEGIN
INSERT INTO audit_trail (mod_type, mod_date, user_key, audit_rec_table, audit_rec_key, audit_rec_key_1,
audit_rec_key_2, is_delta, data_from)
SELECT 'D', GETDATE(), @user_key, 'su_type_code', t.type_code_key, NULL, NULL, 0, audit_data
FROM @d t
END ELSE
BEGIN
INSERT INTO audit_trail (mod_type, mod_date, user_key, audit_rec_table, audit_rec_key, audit_rec_key_1,
audit_rec_key_2, is_delta, data_to, data_from)
SELECT 'U', GETDATE(), @user_key, 'su_type_code', t.type_code_key, NULL, NULL, 0, t.audit_data, d.audit_data
FROM @i t INNER JOIN @d d ON (t.type_code_key = d.type_code_key)
WHERE ISNULL(t.audit_data, '') <> ISNULL(d.audit_data, '')
END
SET NOCOUNT OFF;
答案 2 :(得分:1)
我的工作解决方案是在表格中添加一个唯一的列,就像IDENTITY一样。然后只在该唯一列上加入DELETED和INSERTED。