慢速T-SQL触发器

时间:2011-01-21 15:20:12

标签: performance tsql triggers

我有2个表“Vector”和“VectorElement”。向量具有许多元素,因此Vector和VectorElement之间存在外键关系,具有级联删除 Vector有一个字段VectorSize,其中包含VectorElement中相关记录的数量 显然,这个领域是多余的,但它可以优化性能并使我们的查询简单,因为我们对向量中的元素数量感兴趣。
VectorElement上有一个触发器,用于更新Vector中的VectorSize字段。当一个事务中删除或插入许多Vector记录时,此触发器可以工作但速度很慢 当Vector被删除时,级联删除会删除触发器触发的VectorElements。现在触发器确实更新了待删除的Vector记录,这可能会导致一些麻烦,但插件也会发生这种情况。

这是触发器:

CREATE TRIGGER [TFact].[AfterDeleteInsertVectorElement] 
   ON  [TFact].[VectorElement] 
   AFTER DELETE, INSERT
AS 
BEGIN
    SET NOCOUNT ON;

  WITH cteChangedVectors AS
  ( 
      SELECT DISTINCT i.VectorId 
      FROM inserted i
      UNION 
      SELECT DISTINCT i.VectorId 
      FROM deleted i
  )

    UPDATE 
        TFact.Vector
    SET 
        VectorSize = x.size
    FROM 
        Vector v
    JOIN
        (SELECT VectorId, COUNT(*) as size FROM TFact.VectorElement GROUP BY VectorId) x
        ON v.Id = x.VectorId
    JOIN cteChangedVectors chg ON chg.VectorId = v.Id

END

4 个答案:

答案 0 :(得分:1)

尝试使用索引视图跟踪VectorElements的总数。

请参阅http://technet.microsoft.com/en-us/library/cc917715.aspx#XSLTsection124121120120

SQL Server知道如何有效地跟踪聚合 - 这比每次触发调用启动一条通用程序代码便宜。

如果您使用的是SQL Server Enterprise,只需创建视图,您的查询将被动态重写以使用它们。

像...一样的东西。

CREATE VIEW VectorSize AS
SELECT VectorId, COUNT(*)
FROM Vector NATURAL JOIN VectorElement
GROUP BY VectorId
GO
CREATE UNIQUE CLUSTERED INDEX VectorSizeInd ON VectorSize( VectorId )
然后,SQL Server将在数据库中保持矢量大小的自动更新“硬拷贝”。

答案 1 :(得分:0)

SQL看起来很复杂。如果您期望大型套装,请单独处理

IF EXISTS (SELECT * FROM DELETED)
    UPDATE 
        V
    SET 
        VectorSize = x.size
    FROM 
        Vector V
        JOIN
        (SELECT
             VectorId, COUNT(*) as size
        FROM
             DELETED
        GROUP BY
             VectorId
         ) x
        ON v.Id = x.VectorId
ELSE
    UPDATE 
        V
    SET 
        VectorSize = x.size
    FROM 
        Vector V
        JOIN
        (SELECT
             VectorId, COUNT(*) as size
        FROM
             INSERTED
        GROUP BY
             VectorId
         ) x
        ON v.Id = x.VectorId

答案 2 :(得分:0)

这样更好吗?

UPDATE TFact.Vector
SET    VectorSize = x.size
FROM   Vector v
       inner join (
         select VectorId, count(*) size
         from   TFact.VectorElement
         where  VectorId in (select VectorId from cteChangedVectors)
         group by VectorId
       )x on x.VectorId = v.Id

如果DB gest很大,还要确保你有TFact.VectorElement.VectorId的索引。

关心GJ

答案 3 :(得分:0)

为什么不从插入表和已删除的表中计算“Delta”值,而不是重新计算子表的总和?

 UPDATE
     V
SET
     VectorSize = VectorSize + Delta
FROM
     Vector V
         inner join
     (select VectorID,SUM(Deltas) as Delta from
          (select VectorID,1 as Deltas from inserted union all
           select VectorID,-1 from deleted) t
     group by VectorID
     ) u
         on
            V.VectorID = u.VectorID