У мене є тригер 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+ рядків), це твердження вимагає AGES, навіть якщо я не торкнувся стовпця CUSTCLAS. Я можу спостерігати, як він затримується на цій заяві протягом декількох хвилин у Profiler.
План виконання є химерним. Він показує вкладене сканування з 3 714 виконанням та ~ 18,5 мільйона вихідних рядків. Він проходить через фільтр стовпця 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