web-dev-qa-db-ja.com

更新された行が更新トリガーの代わりにロックされないことがある

ここに小さな再現があります:

create table dbo.t (id int primary key, v int);
insert into dbo.t values (1, 1), (2, 2);

create table dbo.s (id int primary key, v int);
insert into dbo.s values (1, 10);
go

create trigger dbo.tr_t__iou
on dbo.t
instead of update
as
begin
 set nocount on;

 exec sp_lock @@spid;
end;
go

update dbo.t set v = 10 where id = 1;

update t
 set
  v = 10
from
 dbo.s s join
 dbo.t t on t.id = s.id;

update t
 set
  v = 10
from
 (values (1, 10)) s(id, v) join
 dbo.t t on t.id = s.id;
go

drop table dbo.t, dbo.s;
go

sp_locktriggerレポートU -key lock最初のケースと最後のケースで影響を受けた行にありますが、2番目のケースではlockがまったくありません。どのように説明できますか?

6
sepupic

Updateステートメントが取るに足らないプランに該当する場合、ステートメントの代わりのトリガー部分(ExpandInsteadOfTriggerUpd)を展開するオプティマイザールールには、ベーステーブルから読み取るプランの部分が含まれます。この書き換えには、ベースの読み取りにUPDLOCKヒントを追加することが含まれます。通常どおり、UPDLOCKヒントは、更新ロックが取得され、トランザクションの最後まで保持されることを意味します。

ステートメントが簡単なプランに適さない場合、ExpandInsteadOfTriggerUpdルールのみ プランの書き込みカーソル部分を書き換えます 、基本テーブルはそのまま残ります-UPDLOCKヒントが追加されました。

私の推測では、この平凡な計画の振る舞いは、デッドロックシナリオを回避するために存在していると思います。

8
Paul White 9