有时更新的行没有被锁定而不是更新触发器

sep*_*pic 7 trigger sql-server t-sql locking

这是一个小的repro:

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
Run Code Online (Sandbox Code Playgroud)

sp_lock在第一种和最后一种情况下受影响行的trigger报告 U- 中key lock,但在第二种情况下根本没有lock,如何解释?

Pau*_*ite 9

当更新语句符合普通计划的条件时,扩展语句 ( ExpandInsteadOfTriggerUpd)的替代触发器部分的优化器规则包括从基表读取的计划部分。此重写包括向UPDLOCK基本读取添加提示。像往常一样,UPDLOCK提示意味着获取更新锁并保持到事务结束。

当该语句不符合简单计划的条件时,ExpandInsteadOfTriggerUpd规则仅重写计划的写游标部分,而保持基表读取不变 - 不UPDLOCK添加任何提示。

我的猜测是,这种微不足道的计划行为的存在是为了避免死锁场景。