Mam wyzwalacz UPDATE w tabeli, która szuka konkretnej kolumny zmieniającej się z jednej określonej wartości na dowolną inną. Gdy tak się dzieje, aktualizuje niektóre powiązane dane w innej tabeli za pomocą pojedynczej instrukcji UPDATE.
Pierwszą rzeczą, którą robi wyzwalacz, jest sprawdzenie, czy którykolwiek z zaktualizowanych wierszy zmienił wartość tej kolumny w stosunku do wartości, o której mowa. Po prostu łączy INSERTED z DELETED i porównuje wartość w tej kolumnie. Jeśli nic się nie kwalifikuje, następuje wczesne ratowanie, więc instrukcja UPDATE nie działa.
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
W takim przypadku CUSTNMBR jest kluczem podstawowym tabeli bazowej. Jeśli wykonam dużą aktualizację w tej tabeli (powiedzmy, ponad 5000 wierszy), to oświadczenie zajmie WIEK, nawet jeśli nie dotknąłem kolumny CUSTCLAS. Mogę obserwować, jak utknął na tym oświadczeniu przez kilka minut w Profiler.
Plan wykonania jest dziwaczny. Pokazuje Wstawione skanowanie z 3714 wykonaniami i ~ 18,5 milionami wierszy wyjściowych. To działa przez filtr w kolumnie CUSTCLAS. Łączy to (poprzez zagnieżdżoną pętlę) z usuniętym skanem (również filtrowanym w CUSTCLAS), który wykonuje się tylko raz i ma 5000 wierszy wyjściowych.
Jaką idiotyczną rzecz tutaj robię, żeby to spowodować? Pamiętaj, że wyzwalacz absolutnie musi poprawnie obsługiwać aktualizacje w wielu wierszach.
EDYCJA :
Próbowałem też napisać to w ten sposób (na wypadek, gdyby EXISTS robił coś nieprzyjemnego), ale wciąż jest tak samo okropne.
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