web-dev-qa-db-fra.com

Parfois, les lignes mises à jour ne sont pas verrouillées à la place du déclencheur de mise à jour

Voici une petite 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

sp_lock dans les trigger rapports U -key lock sur la ligne affectée dans le premier et le dernier cas, mais dans le second cas il n'y a pas du tout de lock, comment l'expliquer?

6
sepupic

Lorsque l'instruction de mise à jour se qualifie pour un plan trivial, la règle d'optimisation qui développe la partie déclencheur à la place de l'instruction (ExpandInsteadOfTriggerUpd) inclut la partie du plan qui lit à partir de la table de base. Cette réécriture comprend l'ajout d'un indice UPDLOCK à la lecture de base. Comme d'habitude, l'indicateur UPDLOCK signifie que les verrous de mise à jour sont pris et maintenus jusqu'à la fin de la transaction.

Lorsque l'instruction ne remplit pas les conditions requises pour un plan trivial, la règle ExpandInsteadOfTriggerUpd uniquement réécrit la partie écriture-curseur du plan, laissant la table de base lue intacte - pas de UPDLOCK un indice est ajouté.

Je suppose que ce comportement de plan trivial existe pour éviter un scénario de blocage.

8
Paul White 9