Ho un trigger UPDATE su una tabella che cerca una colonna specifica che cambia da un valore specifico a qualsiasi altro valore. Quando ciò accade, aggiorna alcuni dati correlati in un'altra tabella tramite una singola istruzione UPDATE.
La prima cosa che fa il trigger è verificare se le righe aggiornate hanno cambiato il valore di questa colonna rispetto al valore in questione. Unisce semplicemente INSERTED a DELETED e confronta il valore in quella colonna. Se nulla si qualifica, viene salvato in anticipo quindi l'istruzione UPDATE non viene eseguita.
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 questo caso, CUSTNMBR è la chiave primaria della tabella sottostante. Se eseguo un aggiornamento di grandi dimensioni su questa tabella (diciamo, oltre 5000 righe), questa istruzione prende AGES, anche se non ho toccato la colonna CUSTCLAS. Posso vederlo bloccato su questa affermazione per diversi minuti in Profiler.
Il piano di esecuzione è bizzarro. Mostra una scansione inserita con 3.714 esecuzioni e ~ 18,5 milioni di righe di output. Ciò attraversa un filtro nella colonna CUSTCLAS. Unisce questo (tramite loop nidificato) a una scansione eliminata (filtrata anche su CUSTCLAS), che viene eseguita una sola volta e ha 5000 righe di output.
Che cosa idiota sto facendo qui per causare questo? Si noti che il trigger deve assolutamente gestire correttamente gli aggiornamenti multi-riga.
MODIFICA :
Ho anche provato a scriverlo in questo modo (nel caso EXISTS stesse facendo qualcosa di spiacevole), ma è comunque altrettanto terribile.
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