Sql server 用于更新insert和delete上的总记录的触发器

Sql server 用于更新insert和delete上的总记录的触发器,sql-server,triggers,Sql Server,Triggers,我正在编写一个触发器,将一个表的记录计数作为列存储在另一个表中,以加速大型数据库上的一些报告查询 这是我到目前为止得到的,它可以很好地处理删除操作,但我还需要处理插入操作。我需要使用单独的触发器吗?另外,使用光标是必要的还是有更有效的方法 谢谢 ALTER TRIGGER [dbo].[updateSourceTotals] ON [dbo].imports AFTER INSERT, DELETE AS BEGIN SET NOCOUNT ON; DECLA

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

这是我到目前为止得到的,它可以很好地处理删除操作,但我还需要处理插入操作。我需要使用单独的触发器吗?另外,使用光标是必要的还是有更有效的方法

谢谢

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

如果您真的选择了触发器方法,我不推荐使用它,那么这是您当前代码的一个更简单、可能更快的版本:

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
如果您还想覆盖插件,则应这样做:

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
作为一个额外的好处,它应该也适用于更新

需要澄清的是,在触发器中进行预聚合(即使在消除游标之后)的问题在于,不是在每个请求上重新计算查询,而是在每次修改时重新计算查询


即使在抽象的情况下,如果您执行了许多这样的请求,但没有对表进行太多修改,这也只是一个胜利。然而,在活动DBMS服务器的实际环境中,您甚至会失去这一小优势,因为如果您发出许多这样的请求,那么它们可能会得到非常有效的缓存,因为读缓存比写缓存有效得多。

到底为什么您需要通过触发器更新计数?您总是可以在运行时获得该计数,并且它不依赖于带有游标的触发器,甚至更少。如果在选择时间获得计数是昂贵的,那么考虑索引视图。应该删除此触发器和totalImports列。通常,预先计算的聚合不是解决报告性能的一种可取方法,特别是考虑到它们的非关系性质。然而,如果你的报告是这样写的,那么我可以理解为什么它们写得慢。但是,解决方案并不是使用一个会使插入和删除速度极其缓慢的触发器。更可能的解决方案是优化报表及其表和索引。这是一个示例,其中还使用了更复杂的聚合,它们需要实时数据,因此我认为在底层记录更改时计算一次,而不是每次请求时计算一次是有意义的。不过,我完全支持其他方法,但它确实需要持久化,而不是在运行时计算。这不起作用-如果我运行一个简单的UPDATE sources SET label=label来更新所有行,它会计算totalImports,但数字都错了。我认为对于一个更新,它必须每行工作,或者至少每一个sourceId工作?这确实是每一个sourceId计算的,它只是以一种面向集合的方式进行的。至于更新的问题,我不知道为什么它不能正常工作。你能发布一些示例数据来证明或至少解释它是如何错误的吗?我发现了这个问题。对于具有导入的任何源,它在更新时都可以正常工作,但如果导入计数的结果为零,则它将返回表中的记录总数,而不考虑sourceId。选择id,totalImports,选择COUNT FROM imports WHERE imports.sourceId=sources.id AS-actualImports FROM sources 6 136037 0 7 136037 0 9 136037 0 10 136037 0 11 1873 1873 12 82 13 278 278 14 2762 2762 15 4509 4509抱歉,仍在尝试设置格式,请耐心等待@不要通过编辑你的原创文章并在文章末尾添加它来否定这样的东西。