J'ai un déclencheur UPDATE sur une table qui surveille une colonne spécifique passant d'une valeur spécifique à une autre valeur. Lorsque cela se produit, il met à jour certaines données associées dans une autre table via une seule instruction UPDATE.
La première chose que le déclencheur fait est de vérifier si des lignes mises à jour ont changé la valeur de cette colonne par rapport à la valeur en question. Il joint simplement INSERTED à DELETED et compare la valeur de cette colonne. Si rien ne se qualifie, il sort tôt pour que l'instruction UPDATE ne s'exécute pas.
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
Dans ce cas, CUSTNMBR est la clé primaire de la table sous-jacente. Si je fais une grande mise à jour sur cette table (disons, plus de 5000 lignes), cette instruction prend AGES, même si je n'ai pas touché la colonne CUSTCLAS. Je peux le regarder caler sur cette déclaration pendant plusieurs minutes dans Profiler.
Le plan d'exécution est bizarre. Il montre un scan inséré avec 3 714 exécutions et ~ 18,5 millions de lignes de sortie. Cela passe par un filtre sur la colonne CUSTCLAS. Il joint cela (via une boucle imbriquée) à un balayage supprimé (également filtré sur CUSTCLAS), qui ne s'exécute qu'une seule fois et possède 5000 lignes de sortie.
Quelle chose idiote fais-je ici pour provoquer cela? Notez que le déclencheur doit absolument gérer correctement les mises à jour multi-lignes.
MODIFIER :
J'ai aussi essayé de l'écrire comme ça (au cas où EXISTS faisait quelque chose de désagréable), mais c'est toujours aussi terrible.
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