我在表上有一个UPDATE触发器,该触发器监视从一个特定值更改为任何其他值的特定列。发生这种情况时,它将通过单个UPDATE语句更新另一个表中的一些相关数据。
触发器要做的第一件事是检查是否有任何更新的行使该列的值与所讨论的值发生了变化。它只是将INSERTED与DELETED连接起来,并比较该列中的值。如果没有任何条件,它将尽早解决,因此UPDATE语句不会运行。
IF NOT EXISTS (
SELECT TOP 1 i.CUSTNMBR
FROM INSERTED i
INNER JOIN DELETED d
ON i.CUSTNMBR = d.CUSTNMBR
WHERE d.CUSTCLAS = 'Misc'
AND i.CUSTCLAS != 'Misc'
)
RETURN
在这种情况下,CUSTNMBR是基础表的主键。如果我对此表进行了大的更新(例如,超过5000行),则即使我没有触摸CUSTCLAS列,该语句也需要AGES。我可以在Profiler中看到它在此语句上停滞了几分钟。
执行计划很奇怪。它显示了具有3,714次执行和约1,850万个输出行的插入扫描。通过CUSTCLAS列上的过滤器运行。它将其(通过嵌套循环)连接到“删除的扫描”(也已在CUSTCLAS上过滤),该“删除的扫描”仅执行一次并且有5000条输出行。
我在这里做什么愚蠢的事情导致这个?请注意,触发器绝对必须正确处理多行更新。
编辑:
我也尝试过这样写(以防EXISTS做不愉快的事情),但它仍然一样糟糕。
DECLARE @CUSTNMBR varchar(31)
SELECT TOP 1 @CUSTNMBR = i.CUSTNMBR
FROM INSERTED i
INNER JOIN DELETED d
ON i.CUSTNMBR = d.CUSTNMBR
WHERE d.CUSTCLAS = 'Misc'
AND i.CUSTCLAS != 'Misc'
IF @CUSTNMBR IS NULL
RETURN