Eu tenho um gatilho UPDATE em uma tabela que observa uma coluna específica mudar de um valor específico para qualquer outro valor. Quando isso acontece, ele atualiza alguns dados relacionados em outra tabela por meio de uma única instrução UPDATE.
A primeira coisa que o gatilho faz é verificar se alguma linha atualizada teve o valor dessa coluna alterado do valor em questão. Simplesmente associa INSERTED a DELETED e compara o valor nessa coluna. Se nada for qualificado, ele será desativado mais cedo, para que a instrução UPDATE não seja executada.
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
Nesse caso, CUSTNMBR é a chave primária da tabela subjacente. Se eu fizer uma grande atualização nesta tabela (digamos, mais de 5000 linhas), essa declaração levará AGES, mesmo que eu não tenha tocado na coluna CUSTCLAS. Eu posso vê-lo parar nesta declaração por vários minutos no Profiler.
O plano de execução é bizarro. Ele mostra uma verificação inserida com 3.714 execuções e ~ 18,5 milhões de linhas de saída. Isso é executado através de um filtro na coluna CUSTCLAS. Ele une isso (via loop aninhado) a uma Varredura excluída (também filtrada no CUSTCLAS), que é executada apenas uma vez e possui 5000 linhas de saída.
Que coisa idiota que estou fazendo aqui para causar isso? Observe que o gatilho absolutamente deve lidar adequadamente com atualizações de várias linhas.
EDIT :
Eu também tentei escrever assim (no caso EXISTS estava fazendo algo desagradável), mas ainda assim é terrível.
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