web-dev-qa-db-fra.com

Conflit de mise à jour incertaine

J'ai deux questions:

1. Pourquoi est-ce que je reçois un conflit de mise à jour dans cette situation au lieu de bloquer simplement :

-- prepare
drop database if exists [TestSI];
go
create database [TestSI];
go
alter database [TestSI] set READ_COMMITTED_SNAPSHOT ON;
alter database [TestSI] set ALLOW_SNAPSHOT_ISOLATION ON;
go
use [TestSI];
go
drop table if exists dbo.call_test;
create table dbo.call_test ( Id bigint CONSTRAINT [PK_Call] PRIMARY KEY CLUSTERED ( [Id] ASC ), additional int, incl int );
create index ix_Call on dbo.call_test ( additional ) include( incl );
insert into dbo.call_test select 1, 2, 3;
go

Première session:

use [TestSI];
go
set transaction isolation level snapshot
begin tran

   UPDATE dbo.call_test SET additional = 22 WHERE [Id] = 1

Et deuxième session:

use [TestSI];
go
set transaction isolation level snapshot

   UPDATE dbo.call_test SET additional = 222 WHERE [Id] = 1

Dans la deuxième session, je reçois immédiatement:

MSG 3960, niveau 16, état 3, ligne 3 Installation d'instantané Transaction d'isolation abandonnée en raison du conflit de mise à jour. Vous ne pouvez pas utiliser l'isolement d'instantané pour accéder à la table 'dbo.call_test' directement ou indirectement dans la base de données 'Testsi' pour mettre à jour, supprimer ou insérer la ligne modifiée ou supprimée par une autre transaction. Réessayez la transaction ou modifiez le niveau d'isolement pour l'instruction UPDATE/Supprimer.

Ce comportement que j'ai aussi si je mettant à jour inclure la colonne incl au lieu de la clé d'index non clustée.

Quel est l'impact d'un indice non clusterifié sur la mise à jour des conflits dans cette situation? Pourquoi les serrures ne sont-elles pas utilisées dans cette situation?

2. Et la deuxième question théorique :

Comment SQL Server Manche-t-il incluent la mise à jour des colonnes?

Je veux dire comment SQL Server met-il à jour tous les index non clusterés qui ont une colonne include lorsque nous mettons à jour cette valeur? Je ne vois rien de liaison dans le plan de requête.

select @@version

Microsoft SQL Server 2016 (SP2) (KB4052908) - 13.0.5026.0 (X64) mars 2018 09:11:49 Copyright (c) Edition de développeur Microsoft Corporation (64 bits) sur Windows 10 Pro 10.0 (Construction 18363 :) (Hyperviseur )

J'ai vérifié cet exemple sur SQL Server 2019 et le comportement sur ce serveur est tel que prévu: la deuxième session est verrouillée. Est-ce un bug ou j'ai fait quelque chose de mal?

13
Pavel Zv
  1. Et la deuxième question théorique:

Comment SQL Server Manche-t-il incluent la mise à jour des colonnes?
[.____], je veux dire comment SQL Server met-il à jour tous les index non clusterés qui ont une colonne include lorsque nous mettons à jour cette valeur? Je ne vois rien de liaison dans le plan de requête.

Je ne suis pas sûr de comprendre ce qui se passe avec le premier point et je trouve la différence de comportement entre SQL Server 2017 et 2019 pour être encore plus intéressante, mais je peux aider à supprimer le mystère ici.

Les mises à jour index non clusteries ne sont pas affichées dans le plan d'exécution graphique SSMS, mais vous pouvez le voir mentionné dans le XML:

  <Update DMLRequestSort="false">
    <Object Database="[TestSI]" Schema="[dbo]" Table="[call_test]" Index="[PK_Call]" IndexKind="Clustered" Storage="RowStore" />
    <Object Database="[TestSI]" Schema="[dbo]" Table="[call_test]" Index="[ix_Call]" IndexKind="NonClustered" Storage="RowStore" />

De plus, Sentry One Plan Explorer place un petit indicateur Nifty sur l'icône de mise à jour pour vous informer que des index non clusters sont mis à jour "dans les coulisses:"

screenshot of plan Explorer showing the NC index updates

C'est ce qu'on appelle un "plan de mise à jour étroit", au moins auprès du moins familier (je ne vois pas cela dans les documents officiels nulle part). Vous pouvez voir un exemple de différence entre les plans de mise à jour étroits et larges de ce courrier de blogs de Paul White: optimiser les requêtes T-SQL qui modifient les données

10
Josh Darnell