审计表的SQL触发器不同步

时间:2014-02-10 09:22:52

标签: sql-server tsql triggers counter audit-logging

我最近创建了一个SQL触发器来替换我以前运行的非常昂贵的查询,以减少我的数据库每天所做的更新量。

在我进行更新之前,我会检查当天已经发生了多少次更新,这通常是通过查询来完成的:

SELECT COUNT(*) FROM Movies WHERE DateAdded = Date.Now

我的数据库有超过100万条记录,这个查询每分钟运行1-2k左右,所以你可以看到我为什么要为此采用新的方法。

因此,当在Movie表上发生任何INSERT或UPDATE时,我创建了一个审计表并设置了一个SQL触发器来更新此表。但是我注意到审计表每天都不同步几百(审计表计数高于电影表中的实际更新)。由于这不会造成很大的问题,我只是好奇可能导致这种情况或如何进行调试?

SQL触发器:

ALTER TRIGGER [dbo].[trg_Audit]
ON [dbo].[Movies]
AFTER UPDATE, INSERT
AS
BEGIN
    UPDATE Audit SET [count] = [count] + 1 WHERE [date] = CONVERT (date, GETDATE())
    IF @@ROWCOUNT=0
    INSERT INTO audit ([date], [count]) VALUES (GETDATE(), 1)
END

上述触发器仅在Movie表上的UPDATE或INSERT之后发生,并尝试更新Audit表中的count + 1,如果它不存在(IF @@ ROWCOUNT = 0),则它会创建它。任何帮助将非常感激!感谢。

2 个答案:

答案 0 :(得分:2)

这样的事情应该有效:

create table dbo.Movies (
    A int not null,
    B int not null,
    DateAdded datetime not null
)
go
create view dbo.audit
with schemabinding
as
    select CONVERT(date,DateAdded) as dt,COUNT_BIG(*) as cnt
    from dbo.Movies
    group by CONVERT(date,DateAdded)
go
create unique clustered index IX_MovieCounts on dbo.audit (dt)

这称为indexed view。优点是SQL Server负责维护存储在此视图中的数据,而且它始终是正确的。

除非您使用的是Enterprise / Developer版,否则您需要使用audit提示查询NOEXPAND视图:

SELECT * from audit with (noexpand)

这有以下优点

a)您现在不必自己编写触发器(SQL Server确实有一些与幕后触发器非常相似的东西),

b)它现在可以处理多行插入,更新和删除,以及

c)您不必编写逻辑来应对更改DateAdded值的更新。

答案 1 :(得分:1)

不是将计数递增1,而应该将它增加一个已经改变的记录数。例如

UPDATE Audit 
SET [count] = [count] + (SELECT COUNT(*) FROM INSERTED)
WHERE [date] = CONVERT (date, GETDATE())
IF @@ROWCOUNT=0
INSERT INTO audit ([date], [count]) 
VALUES (GETDATE(), (SELECT COUNT(*) FROM INSERTED))