Ich habe einen UPDATE-Trigger für eine Tabelle, die nach einer bestimmten Spalte sucht, die von einem bestimmten Wert zu einem anderen Wert wechselt. In diesem Fall werden einige verwandte Daten in einer anderen Tabelle über eine einzelne UPDATE-Anweisung aktualisiert.
Der Trigger überprüft zunächst, ob bei aktualisierten Zeilen der Wert dieser Spalte gegenüber dem betreffenden Wert geändert wurde. Es verbindet einfach INSERTED mit DELETED und vergleicht den Wert in dieser Spalte. Wenn nichts qualifiziert ist, wird es vorzeitig beendet, sodass die UPDATE-Anweisung nicht ausgeführt wird.
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
In diesem Fall ist CUSTNMBR der Primärschlüssel der zugrunde liegenden Tabelle. Wenn ich eine große Aktualisierung dieser Tabelle durchführe (z. B. mehr als 5000 Zeilen), benötigt diese Anweisung AGES, auch wenn ich die Spalte CUSTCLAS nicht berührt habe. Ich kann beobachten, wie diese Aussage für einige Minuten in Profiler zum Stillstand kommt.
Der Ausführungsplan ist bizarr. Es zeigt einen eingefügten Scan mit 3.714 Ausführungen und ~ 18,5 Millionen Ausgabezeilen. Das läuft durch einen Filter in der CUSTCLAS-Spalte. Es verbindet dies (über eine verschachtelte Schleife) mit einem gelöschten Scan (ebenfalls nach CUSTCLAS gefiltert), der nur einmal ausgeführt wird und 5000 Ausgabezeilen hat.
Was für eine idiotische Sache mache ich hier, um das zu verursachen? Beachten Sie, dass der Trigger mehrzeilige Aktualisierungen unbedingt ordnungsgemäß verarbeiten muss.
EDIT :
Ich habe auch versucht, es so zu schreiben (falls EXISTS etwas Unangenehmes tat), aber es ist immer noch genauso schrecklich.
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