0

我正在编写一个触发器来将一个表的记录计数存储为另一个表中的列,以加快大型数据库上的一些报告查询。

这是我到目前为止所得到的,它在删除时工作得很好,但我也需要它在插入时工作。我需要使用单独的触发器吗?另外,是否有必要使用游标,还是有更有效的方法?

谢谢!

ALTER TRIGGER [dbo].[updateSourceTotals]
   ON  [dbo].imports
   AFTER INSERT, DELETE
AS 
BEGIN

    SET NOCOUNT ON;

    DECLARE @sourceId int;

    DECLARE deleteCursor CURSOR FOR SELECT DISTINCT sourceId FROM deleted

    OPEN deleteCursor

    FETCH NEXT FROM deleteCursor INTO @sourceId

    WHILE @@FETCH_STATUS = 0
    BEGIN

        UPDATE  sources
        SET     totalImports = (
                    SELECT  COUNT(*) 
                    FROM    imports 
                    WHERE   sourceId = @sourceId
                    )
        WHERE   id = @sourceId

    FETCH NEXT FROM deleteCursor INTO @sourceId
    END

    CLOSE deleteCursor
    DEALLOCATE deleteCursor 

END
GO
4

1 回答 1

2

如果您真的设置了触发方法(我推荐它),那么这是您当前代码的一个更简单且可能更快的版本:

ALTER TRIGGER [dbo].[updateSourceTotals]
   ON  [dbo].imports
   AFTER INSERT, DELETE
AS 
BEGIN

    UPDATE  s
    SET     totalImports = (
                SELECT  COUNT(*) 
                FROM    imports i
                WHERE   i.sourceId = s.Id
                )
    FROM    sources s
    WHERE   s.id IN(SELECT sourceId FROM deleted)

END

如果你还想覆盖INSERTs,应该这样做:

ALTER TRIGGER [dbo].[updateSourceTotals]
   ON  [dbo].imports
   AFTER INSERT, DELETE
AS 
BEGIN

    UPDATE  s
    SET     totalImports = (
                SELECT  COUNT(*) 
                FROM    imports i
                WHERE   i.sourceId = s.id
                )
    FROM    sources s
    WHERE   s.id IN(
                    SELECT sourceId FROM deleted
                UNION
                    SELECT sourceId FROM inserted
                  )

END

作为额外的奖励,它也应该适用于UPDATEs。


澄清一下,在触发器中进行预聚合的问题是,即使您消除了光标,也不是在每个请求上重新计算查询,而是在每次修改时重新计算它们。

即使在抽象的情况下,如果您执行许多此类请求,但不要对表格进行太多修改,这只是一个胜利。然而,在一个活跃的 DBMS 服务器的真实环境中,即使是这个小优势,你也失去了大部分,因为如果你发出许多这样的请求,那么它们可能会被非常有效地缓存(反过来,因为读取更多的是缓存-比写有效)。

于 2013-05-17T16:50:45.513 回答