特定の列が特定の値から他の値に変更されるのを監視するテーブルに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行以上)を実行すると、CUSTCLAS列に触れていなくても、このステートメントでAGESがかかります。プロファイラーでこのステートメントが数分間停止するのを見ることができます。
実行計画は奇妙です。挿入されたスキャンが3,714回実行され、出力行が約1,850万行あります。CUSTCLAS列のフィルターを通過します。これは(ネストされたループを介して)削除されたスキャン(これもCUSTCLASでフィルタリングされます)に結合されます。これは1回だけ実行され、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