Guide des interblocages

S’applique à :SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceAzure Synapse AnalyticsAnalytics Platform System (PDW)

Cet article décrit en détail les interblocages dans SQL Server Moteur de base de données. Les blocages sont provoqués par des verrous concurrents et simultanés dans la base de données, souvent dans les transactions en plusieurs étapes. Pour plus d’informations sur le verrouillage des transactions, consultez le guide de verrouillage des transactions et de contrôle de version des lignes.

Pour plus d’informations sur l’identification et la prévention des interblocages dans Azure SQL Database, consultez Analyser et empêcher les interblocages dans Azure SQL Database.

Comprendre les interblocages

Un interblocage se produit lorsque deux tâches ou plus se bloquent mutuellement de façon permanente. Dans ce cas, chaque tâche place un verrou sur une ressource que la ou les autres tâches essaient de verrouiller. Par exemple :

  • La transaction A obtient un verrou partagé sur la ligne 1.
  • La transaction B obtient un verrou partagé sur la ligne 2.
  • La transaction A demande un verrou exclusif sur la ligne 2, mais elle est bloquée jusqu’à la fin de la transaction B qui libérera le verrou partagé sur la ligne 2.
  • La transaction B demande un verrou exclusif sur la ligne 1, mais elle est bloquée jusqu’à la fin de la transaction A qui libérera le verrou partagé sur la ligne 1.

La transaction A ne peut pas se terminer tant que la transaction B n'est pas terminée, mais la transaction B est bloquée par la transaction A. Il s'agit d'une dépendance cyclique : la transaction A est dépendante de la transaction B, mais celle-ci ne peut pas s'exécuter car elle est dépendante de la transaction A.

Les deux transactions en interblocage attendent indéfiniment que la situation soit débloquée par un processus externe. le moniteur de blocage sql Server Moteur de base de données régulièrement case activée pour les tâches qui se trouvent dans un interblocage. S'il détecte une situation de dépendance cyclique, il désigne une des tâches comme victime et met fin à sa transaction avec un message d'erreur. Cela permet à l'autre tâche de terminer sa transaction. L'application qui exécutait la transaction abandonnée peut effectuer une nouvelle tentative qui réussit en général une fois que l'autre transaction est terminée.

L'interblocage est souvent confondu avec le blocage ordinaire. Lorsqu'une transaction demande un verrou sur une ressource verrouillée par une autre transaction, elle attend que le verrou soit libéré. Par défaut, les transactions SQL Server n’expirent pas, sauf si LOCK_TIMEOUT est définie. La transaction qui demande le verrou est bloquée, mais pas indéfiniment puisqu'elle n'a rien fait pour bloquer la transaction détenant le verrou. La transaction qui détient le verrou va finir par se terminer et libérer le verrou ; l'autre transaction pourra alors obtenir son verrou et s'exécuter normalement. Les interblocages sont résolus presque immédiatement, tandis que le blocage peut, en théorie, persister indéfiniment. Les interblocages sont parfois appelés « étreintes fatales ».

Une situation d'interblocage peut se produire sur tout système multithread, pas uniquement sur les systèmes de gestion de bases de données relationnelles. Elle peut également concerner des ressources autres que les verrous sur les objets de base de données. Par exemple, un thread dans un système multithread peut acquérir une ou plusieurs ressources (par exemple, des blocs de mémoire). Si la ressource acquise appartient actuellement à un autre thread, le premier thread peut être amené à attendre que le thread propriétaire libère la ressource cible. le thread en attente a une dépendance sur le thread propriétaire de cette ressource particulière. Dans une instance du Moteur de base de données SQL Server, les sessions peuvent s’interblocer lors de l’acquisition de ressources non de base de données, telles que la mémoire ou les threads.

Diagram showing a transaction deadlock.

Dans l’illustration, la transaction T1 est dépendante de la transaction T2 pour la ressource de Part verrou de table. De même, la transaction T2 est dépendante de la transaction T1 pour la ressource de Supplier verrou de table. Comme ces dépendances forment un cycle, il y a interblocage entre les transactions T1 et T2.

Des interblocages peuvent également se produire quand une table est partitionnée et que le paramètre LOCK_ESCALATION de ALTER TABLE a la valeur AUTO. Lorsqu’elle LOCK_ESCALATION est définie sur AUTO, la concurrence augmente en autorisant l’Moteur de base de données SQL Server à verrouiller les partitions de table au niveau HoBT au lieu du niveau de la table. Toutefois, lorsque des transactions distinctes maintiennent des verrous de partition dans une table et souhaitent un verrou sur l'autre partition de transactions, cela provoque un interblocage. Ce type d’interblocage peut être évité en affectant à LOCK_ESCALATION la valeur TABLE, bien que ce paramètre réduise la concurrence en forçant les mises à jour volumineuses d’une partition à attendre un verrou de table.

Détecter et mettre fin aux interblocages

Un interblocage se produit lorsque deux tâches ou plus se bloquent mutuellement de façon permanente. Dans ce cas, chaque tâche place un verrou sur une ressource que la ou les autres tâches essaient de verrouiller. Le graphique suivant présente un aperçu d'un état de blocage où :

  • La tâche T1 a placé un verrou sur la ressource R1 (indiquée par la flèche reliant R1 à T1) et a demandé un verrou sur la ressource R2 (indiquée par la flèche reliant T1 à R2).
  • La tâche T2 a placé un verrou sur la ressource R2 (indiquée par la flèche reliant R2 à T2) et a demandé un verrou sur la ressource R1 (indiquée par la flèche reliant T2 à R1).
  • Dans la mesure où aucune des deux tâches ne peut continuer tant qu'il n'y a pas de ressource disponible et que ni l'une ni l'autre des ressources ne peut être libérée avant la poursuite d'une tâche, un état de blocage se produit.

Diagram showing the tasks in a deadlock state.

SQL Server Moteur de base de données détecte automatiquement les cycles d’interblocage dans SQL Server. SQL Server Moteur de base de données choisit l’une des sessions en tant que victime d’interblocage et la transaction actuelle est arrêtée avec une erreur pour interrompre le blocage.

Ressources qui peuvent bloquer

Chaque session utilisateur peut avoir une ou plusieurs tâches en cours d'exécution, chacune de ces tâches pouvant obtenir ou être en attente d'obtention de diverses ressources. Les types de ressources susceptibles de provoquer un blocage sont les suivants :

  • Verrous. L’attente d’acquérir des verrous sur des ressources, telles que des objets, des pages, des lignes, des métadonnées et des applications, peut entraîner un blocage. Par exemple, la transaction T1 a un verrou partagé (S) sur la ligne r1 et elle attend d'obtenir un verrou exclusif (X) sur r2. La transaction T2 a un verrou partagé (S) sur r2 et elle attend d'obtenir un verrou exclusif (X) sur la ligne r1. Il en résulte un cycle de verrouillage où T1 et T2 attendent l'une de l'autre la libération des ressources que chacune a verrouillées.

  • Threads de travail. Une tâche mise en file d’attente en attente d’un thread de travail disponible peut entraîner un blocage. Si la tâche en file d'attente est propriétaire des ressources qui bloquent tous les threads de travail, un blocage en résulte. Par exemple, la session S1 démarre une transaction et obtient un verrou partagé (S) sur la ligne r1 pour ensuite se mettre en veille. Les sessions actives en cours d'exécution sur tous les threads de travail disponibles essaient d'obtenir des verrous exclusifs (X) sur la ligne r1. Étant donné que la session S1 ne peut pas obtenir de thread de travail, elle ne peut pas valider la transaction et libère le verrou au niveau sur la ligne r1. Cela produit un blocage.

  • Mémoire. Lorsque des demandes concurrentes sont en attente d'allocation de mémoire qui ne peut être satisfaite faute de mémoire suffisante, un blocage peut se produire. Par exemple, deux demandes concurrentes, Q1 et Q2, qui s'exécutant en tant que fonctions définies par l'utilisateur, obtiennent respectivement 10 Mo et 20 Mo de mémoire. Si chaque requête nécessite 30 Mo et que la quantité de mémoire disponible est de 20 Mo, Q1 et Q2 doivent attendre que chacune libère la mémoire, ce qui entraîne un blocage.

  • Ressources liées à l’exécution de requêtes parallèles. Les threads coordinateurs, producteurs ou consommateurs associés à un port d’échange peuvent se bloquer mutuellement à l’origine d’un interblocage généralement lorsqu’il s’agit d’au moins un autre processus qui ne fait pas partie de la requête parallèle. En outre, lorsqu’une requête parallèle démarre l’exécution, SQL Server détermine le degré de parallélisme, ou le nombre de threads de travail, en fonction de la charge de travail actuelle. Si la charge de travail change de façon inattendue, par exemple si de nouvelles requêtes commencent à s'exécuter sur le serveur ou que le système se trouve à court de threads de travail, il peut s'ensuivre un blocage.

  • Ressources MARS (Multiple Active Result Sets). Ces ressources servent à contrôler l'entrelacement de plusieurs demandes actives sous MARS. Pour plus d’informations, consultez Utilisation de MARS (Multiple Active Result Sets).

    • Ressource utilisateur. Lorsqu'un thread est en attente d'une ressource potentiellement contrôlée par une application d'utilisateur, la ressource est considérée comme étant une ressource externe ou utilisateur et est traitée comme un verrou.

    • Exclusion mutuelle de session. Les tâches exécutées au cours d'une session sont entrelacées, ce qui signifie que seule une tâche peut s'exécuter à un moment donné dans le cadre de la session. Avant de pouvoir s'exécuter, la tâche doit disposer d'un accès exclusif à l'exclusion mutuelle de la session.

    • Exclusion mutuelle de transaction. Toutes les tâches qui s'exécutent lors d'une transaction sont entrelacées, ce qui signifie que seule une tâche peut s'exécuter à un moment donné dans le cadre de la transaction. Avant de pouvoir s'exécuter, la tâche doit disposer d'un accès exclusif à l'exclusion mutuelle de la transaction.

    Pour pouvoir s'exécuter sous MARS, une tâche doit obtenir l'exclusion mutuelle de session. Si la tâche s'exécute dans le cadre d'une transaction, elle doit obtenir l'exclusion mutuelle de transaction. Vous serez ainsi assuré qu'il n'y a qu'une seule tâche active à la fois pour une session et une transaction données. Dès lors que les exclusions mutuelles requises ont été acquises, la tâche peut s'exécuter. Quand la tâche est terminée ou qu'elle aboutit au milieu de la demande, elle libère l'exclusion mutuelle de transaction avant l'exclusion mutuelle de session, c'est-à-dire dans l'ordre inverse de leur acquisition. Cependant, des blocages peuvent se produire avec ces ressources. Dans le pseudocode suivant, deux tâches, la demande utilisateur U1 et la demande utilisateur U2, s’exécutent dans la même session.

    U1:    Rs1=Command1.Execute("insert sometable EXEC usp_someproc");  
    U2:    Rs2=Command2.Execute("select colA from sometable");  
    

    La procédure stockée qui s'exécute à partir de la demande d'utilisateur U1 a obtenu l'exclusion mutuelle de session. Si la procédure stockée prend beaucoup de temps à s’exécuter, il est supposé que SQL Server Moteur de base de données que la procédure stockée attend l’entrée de l’utilisateur. La demande d'utilisateur U2 attend l'exclusion mutuelle de session alors que l'utilisateur attend le jeu de résultats d'U2, et U1 attend une ressource utilisateur. Il s'agit d'un état de blocage logiquement illustré ainsi :

    Diagram of the logical flow of a stored procedure in MARS.

Détection d’interblocage

Toutes les ressources répertoriées dans la section ci-dessus participent au schéma de détection de blocage sql Server Moteur de base de données. La détection de blocage est effectuée par un thread de moniteur de verrouillage qui lance régulièrement une recherche dans toutes les tâches d’une instance de SQL Server Moteur de base de données. Le processus de recherche présente les caractéristiques suivantes :

  • L'intervalle par défaut est de 5 secondes.
  • Si le thread de contrôle des verrous détecte des blocages, de 5 secondes, l'intervalle de détection de blocage pourra descendre jusqu'à 100 millisecondes, en fonction de la fréquence des blocages.
  • Si le thread du moniteur de verrouillage cesse de trouver des interblocages, sql Server Moteur de base de données augmente les intervalles entre les recherches à 5 secondes.
  • Si un blocage vient d'être détecté, les prochains threads qui doivent attendre un verrou sont supposés entrer dans le cycle de blocage. Les deux premières attentes de verrous postérieures à une détection de blocage déclencheront immédiatement une recherche de blocage sans attendre le prochain intervalle de détection de blocage. Par exemple, si l'intervalle courant est de 5 secondes et qu'un blocage vient d'être détecté, la prochaine attente de verrou lancera immédiatement le détecteur de blocage. Si cette attente de verrou est impliquée dans un blocage, celui-ci sera détecté sur le champ et non lors de la prochaine recherche de blocage.

SQL Server Moteur de base de données effectue généralement une détection périodique des interblocages uniquement. Puisque le nombre de blocages rencontrés dans le système est généralement faible, la détection de blocages périodique permet de réduire l'intendance des détections de blocage dans le système.

Lorsque le contrôleur de verrous initialise une recherche de blocage pour une thread particulière, il identifie la ressource sur laquelle le thread est en attente. Il recherche ensuite le ou les propriétaires de la ressource concernée et continue la recherche de façon récursive, jusqu'à ce qu'il trouve un cycle. Un cycle identifié de cette manière forme un blocage.

Une fois qu’un blocage est détecté, sql Server Moteur de base de données met fin à un interblocage en choisissant l’un des threads comme victime d’interblocage. SQL Server Moteur de base de données met fin au lot en cours d’exécution pour le thread, restaure la transaction de la victime du blocage et retourne une erreur 1205 à l’application. L'annulation de la transaction de la victime du blocage a pour effet de libérer tous les verrous détenus par la transaction. Cela permet aux transactions des autres threads de se débloquer et de continuer. L'erreur de victime de blocage 1205 enregistre des informations sur les threads et les ressources impliqués dans un blocage dans le journal des erreurs.

Par défaut, sql Server Moteur de base de données choisit comme victime de blocage la session exécutant la transaction qui est moins coûteuse à restaurer. Un utilisateur peut également spécifier la priorité des sessions dans une situation de blocage au moyen de l’instruction SET DEADLOCK_PRIORITY. DEADLOCK_PRIORITY accepte les valeurs LOW, NORMAL ou HIGH, voire toute valeur entière comprise entre -10 et 10. La valeur par défaut de la priorité de blocage est NORMAL. Si deux sessions ont des priorités de blocage différentes, c'est la session qui a la priorité la plus basse qui est choisie comme victime. Si les deux sessions ont la même priorité de blocage, c'est celle dont la transaction est la moins coûteuse à annuler qui est choisie. Si les sessions impliquées dans le cycle de blocage présentent une priorité de blocage et un coût identiques, la victime est choisie de façon aléatoire.

Lorsque les fonctionnalités CLR sont utilisées, le moniteur de blocage détecte automatiquement le blocage des ressources de synchronisation (moniteurs, verrou de lecture/écriture et jointure de thread) qui font l'objet d'accès à l'intérieur des procédures gérées. Toutefois, le blocage est résolu par la levée d'une exception dans la procédure qui a été sélectionnée comme victime du blocage. Il est important de comprendre que l'exception ne libère pas automatiquement les ressources actuellement détenues par la victime ; les ressources doivent être libérées explicitement. Conformément au comportement des exceptions, l'exception utilisée pour identifier une victime de blocage peut être interceptée et annulée.

Outils d’informations sur le blocage

Pour afficher les informations de blocage, l’Moteur de base de données SQL Server fournit des outils de surveillance sous la forme de la system_health session xEvent, deux indicateurs de trace et l’événement de graphe d’interblocage dans SQL Profiler.

Remarque

Cette section contient des informations sur les événements étendus, les indicateurs de trace et les traces, mais l’événement étendu Deadlock est la méthode recommandée pour capturer les informations de blocage.

Événement étendu d’interblocage

À compter de SQL Server 2012 (11.x), l’événement xml_deadlock_report étendu (xEvent) doit être utilisé au lieu de la classe d’événements de graphe deadlock dans SQL Trace ou SQL Profiler.

À compter de SQL Server 2012 (11.x), lorsque des interblocages se produisent, la system_health session capture déjà tous les xml_deadlock_report xEvents qui contiennent le graphique de blocage. Étant donné que la session system_health est activée par défaut, il n’est pas nécessaire qu’une session xEvent distincte soit configurée pour capturer les informations de blocage. Aucune action supplémentaire n’est requise pour capturer les informations d’interblocage avec le xml_deadlock_report.

L’événement Deadlock Graph capturé a généralement trois nœuds distincts :

  • victim-list. Identificateur du processus victime de l’interblocage.
  • process-list. Informations sur tous les processus impliqués dans l’interblocage.
  • resource-list. Informations sur les ressources impliquées dans l’interblocage.

L’ouverture du fichier de session ou de la system_health mémoire tampon en anneau, si l’événement xml_deadlock_report xEvent est enregistré, Management Studio présente une représentation graphique des tâches et des ressources impliquées dans un blocage, comme illustré dans l’exemple suivant :

A screenshot from SSMS of a XEvent Deadlock Graph visual diagram.

La requête suivante peut afficher tous les événements de blocage capturés par la mémoire tampon en anneau de system_health session :

SELECT xdr.value('@timestamp', 'datetime') AS [Date],
    xdr.query('.') AS [Event_Data]
FROM (SELECT CAST([target_data] AS XML) AS Target_Data
            FROM sys.dm_xe_session_targets AS xt
            INNER JOIN sys.dm_xe_sessions AS xs ON xs.address = xt.event_session_address
            WHERE xs.name = N'system_health'
              AND xt.target_name = N'ring_buffer'
    ) AS XML_Data
CROSS APPLY Target_Data.nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS XEventData(xdr)
ORDER BY [Date] DESC;

Voici le jeu de résultats obtenu.

A screenshot from SSMS of the system_health xEvent query result.

L’exemple suivant montre la sortie, après avoir sélectionné le premier lien du résultat ci-dessus :

<event name="xml_deadlock_report" package="sqlserver" timestamp="2022-02-18T08:26:24.698Z">
  <data name="xml_report">
    <type name="xml" package="package0" />
    <value>
      <deadlock>
        <victim-list>
          <victimProcess id="process27b9b0b9848" />
        </victim-list>
        <process-list>
          <process id="process27b9b0b9848" taskpriority="0" logused="0" waitresource="KEY: 5:72057594214350848 (1a39e6095155)" waittime="1631" ownerId="11088595" transactionname="SELECT" lasttranstarted="2022-02-18T00:26:23.073" XDES="0x27b9f79fac0" lockMode="S" schedulerid="9" kpid="15336" status="suspended" spid="62" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2022-02-18T00:26:22.893" lastbatchcompleted="2022-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="7908" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088595" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
            <executionStack>
              <frame procname="AdventureWorks2022.dbo.p1" line="3" stmtstart="78" stmtend="180" sqlhandle="0x0300050020766505ca3e07008ba8000001000000000000000000000000000000000000000000000000000000">
SELECT c2, c3 FROM t1 WHERE c2 BETWEEN @p1 AND @p1+    </frame>
              <frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x020000006263ec01ebb919c335024a072a2699958d3fcce60000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
SET NOCOUNT ON
WHILE (1=1) 
BEGIN
    EXEC p1 4
END
   </inputbuf>
          </process>
          <process id="process27b9ee33c28" taskpriority="0" logused="252" waitresource="KEY: 5:72057594214416384 (e5b3d7e750dd)" waittime="1631" ownerId="11088593" transactionname="UPDATE" lasttranstarted="2022-02-18T00:26:23.073" XDES="0x27ba15a4490" lockMode="X" schedulerid="6" kpid="5584" status="suspended" spid="58" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2022-02-18T00:26:22.890" lastbatchcompleted="2022-02-18T00:26:22.890" lastattention="1900-01-01T00:00:00.890" clientapp="SQLCMD" hostname="ContosoServer" hostpid="15316" loginname="CONTOSO\user" isolationlevel="read committed (2)" xactid="11088593" currentdb="5" lockTimeout="4294967295" clientoption1="538968096" clientoption2="128056">
            <executionStack>
              <frame procname="AdventureWorks2022.dbo.p2" line="3" stmtstart="76" stmtend="150" sqlhandle="0x03000500599a5906ce3e07008ba8000001000000000000000000000000000000000000000000000000000000">
UPDATE t1 SET c2 = c2+1 WHERE c1 = @p    </frame>
              <frame procname="adhoc" line="4" stmtstart="82" stmtend="98" sqlhandle="0x02000000008fe521e5fb1099410048c5743ff7da04b2047b0000000000000000000000000000000000000000">
unknown    </frame>
            </executionStack>
            <inputbuf>
SET NOCOUNT ON
WHILE (1=1) 
BEGIN
    EXEC p2 4
END
   </inputbuf>
          </process>
        </process-list>
        <resource-list>
          <keylock hobtid="72057594214350848" dbid="5" objectname="AdventureWorks2022.dbo.t1" indexname="cidx" id="lock27b9dd26a00" mode="X" associatedObjectId="72057594214350848">
            <owner-list>
              <owner id="process27b9ee33c28" mode="X" />
            </owner-list>
            <waiter-list>
              <waiter id="process27b9b0b9848" mode="S" requestType="wait" />
            </waiter-list>
          </keylock>
          <keylock hobtid="72057594214416384" dbid="5" objectname="AdventureWorks2022.dbo.t1" indexname="idx1" id="lock27afa392600" mode="S" associatedObjectId="72057594214416384">
            <owner-list>
              <owner id="process27b9b0b9848" mode="S" />
            </owner-list>
            <waiter-list>
              <waiter id="process27b9ee33c28" mode="X" requestType="wait" />
            </waiter-list>
          </keylock>
        </resource-list>
      </deadlock>
    </value>
  </data>
</event>

Pour plus d’informations, consultez Utiliser la session system_health

Indicateur de trace 1204 et indicateur de trace 1222

Lorsque des interblocages se produisent, l’indicateur de trace 1204 et l’indicateur de trace 1222 retournent des informations capturées dans le journal des erreurs SQL Server. L’indicateur de trace 1204 signale les informations d’interblocage mises en forme par chaque nœud impliqué dans le blocage. L’indicateur de trace 1222 met en forme les informations de blocage, tout d’abord par processus, puis par ressources. Il est possible d'activer deux indicateurs de trace pour obtenir deux représentations du même événement de blocage.

Important

Évitez d’utiliser l’indicateur de trace 1204 et 1222 sur les systèmes gourmands en charge de travail qui rencontrent des blocages. L’utilisation de ces indicateurs de trace peut entraîner des problèmes de performances. Utilisez plutôt l’événement étendu Deadlock pour capturer les informations nécessaires.

Outre la définition des propriétés de l’indicateur de trace 1204 et 1222, le tableau suivant présente également les similitudes et les différences.

Propriété Indicateur de trace 1204 et indicateur de trace 1222 Indicateur de trace 1204 uniquement Indicateur de trace 1222 uniquement
Format de sortie La sortie est capturée dans le journal des erreurs SQL Server. Les nœuds impliqués dans le blocage sont privilégiés. Chaque nœud dispose d'une section dédiée, tandis que la section finale décrit la victime du blocage. Retourne des informations dans un format de type XML, mais non conforme au schéma XSD (XML Schema Definition). Le format possède trois sections principales. La première déclare la victime du blocage. La deuxième décrit chaque processus impliqué dans le blocage. La troisième section décrit les ressources synonymes de nœuds dans l’indicateur de trace 1204.
Identification d'attributs SPID :<x> ECID :<x>. Identifie le thread de l'ID du processus système en cas de traitements parallèles. L’entrée SPID:<x> ECID:0, où <x> est remplacé par la valeur SPID, représente le thread principal. L’entrée SPID:<x> ECID:<y>, où <x> est remplacé par la valeur SPID et <y> est supérieur à 0, représente les sous-threads pour le même SPID.

BatchID (sbid pour l’indicateur de trace 1222). Identifie le traitement à partir duquel l'exécution du code demande ou détient un verrou. Lorsque MARS (Multiple Active Result Sets) est désactivé, la valeur BatchID est 0. Quand MARS est activé, la valeur des lots actifs est 1 pour n. Si la session ne comporte pas de traitements actifs, BatchID a pour valeur 0.

Mode. Spécifie, pour une ressource particulière, le type de verrou demandé, accordé ou attendu par un thread. Les différents modes sont IS (intent partagé), S (partagé), U (mise à jour), IX (intent exclusif), SIX (partagé avec intent exclusif) et X (exclusif).

Ligne # (ligne pour l’indicateur de trace 1222). Indique le numéro de ligne du traitement qui était en cours d'exécution lorsque le blocage s'est produit.

Buf d’entrée (inputbuf pour l’indicateur de trace 1222). Dresse la liste de toutes les instructions du traitement en cours.
Node. Il s'agit du numéro d'entrée dans la chaîne de blocage.

Lists. Le propriétaire du verrou peut faire partie des listes suivantes :

Grant List. Énumère les propriétaires actuels de la ressource.

Convert List. Énumère les propriétaires en cours qui essaient de convertir leurs verrous vers un niveau supérieur.

Wait List. Énumère les nouvelles demandes de verrou en cours pour la ressource.

Statement Type. Décrit le type d'instructions DML (SELECT, INSERT, UPDATE ou DELETE) sur lesquelles les threads disposent d'autorisations.

Victim Resource Owner. Spécifie le thread participant choisi par SQL Server comme victime pour briser le cycle d’interblocage. Il est alors mis fin au thread choisi et à tous les sous threads existants.

Next Branch. Représente les deux sous threads (ou plus) du même SPID qui participent au cycle de blocage.
deadlock victim. Représente l’adresse de mémoire physique de la tâche (voir sys.dm_os_tasks (Transact-SQL)) qui a été sélectionnée comme victime d’interblocage. Il peut s’agir de 0 (zéro) en cas d’interblocage non résolu. Une tâche en cours d'annulation ne peut pas être choisie comme victime de blocage.

executionstack. Représente le code Transact-SQL en cours d’exécution au moment de l’interblocage.

priority. Représente la priorité de blocage. Dans certains cas, le Moteur de base de données SQL Server peut choisir de modifier la priorité d’interblocage pendant une courte durée afin d’obtenir une meilleure concurrence.

logused. Espace journal utilisé par la tâche.

ID de propriétaire. ID de la transaction qui a le contrôle de la requête.

status. État de la tâche. Il prend l'une des valeurs suivantes :

>>pending. En attente d'un thread de travail.

>>runnable. Prêt à s'exécuter, mais en attente d'un quantum.

>>running. En cours d'exécution sur le planificateur.

>>suspended. L'exécution est suspendue.

>>done. La tâche est achevée.

>>spinloop. En attente de libération d'un spinlock.

waitresource. Ressource convoitée par la tâche.

waittime. Délai d'attente de la ressource en millisecondes.

schedulerid. Planificateur associé à cette tâche. Consultez sys.dm_os_schedulers (Transact-SQL).

hostname. Nom de la station de travail.

isolationlevel. Niveau d'isolement des transactions en cours.

Xactid. ID de la transaction qui contrôle la demande.

currentdb. ID de la base de données.

lastbatchstarted. Dernière fois qu'un processus client a démarré une exécution de traitement.

lastbatchcompleted. Dernière fois qu'un processus client a terminé une exécution de traitement.

clientoption1 et clientoption2. Options définies pour cette connexion cliente. Il s'agit d'un masque de bits qui contient des informations sur les options habituellement contrôlées par les instructions SET, telles que SET NOCOUNT et SET XACTABORT.

associatedObjectId. Représente l'ID HoBT (Heap ou B-tree, segment de mémoire ou arbre B).
Attributs des ressources RID. Identifie la ligne d'une table pour laquelle un verrou est détenu ou demandé. RID est représenté en tant que RID : db_id:file_id:page_no:row_no. Par exemple : RID: 6:1:20789:0.

OBJECT. Identifie la table pour laquelle un verrou est détenu ou demandé. OBJECT est représenté en tant qu’OBJET : db_id:object_id. Par exemple : TAB: 6:2009058193.

KEY. Identifie la plage de clés d'un index pour laquelle un verrou est détenu ou demandé. KEY est représenté sous la forme KEY : db_id:hobt_id (valeur de hachage de clé d’index). Par exemple : KEY: 6:72057594057457664 (350007a4d329).

PAG. Identifie la ressource de page pour laquelle un verrou est détenu ou demandé. PAG est représenté en tant que PAG : db_id:file_id:page_no. Par exemple : PAG: 6:1:20789.

EXT. Identifie la structure d'extension. EXT est représenté comme EXT : db_id:file_id:extent_no. Par exemple : EXT: 6:1:9.

DB. Identifie le verrou de base de données. DB est représenté de l’une des manières suivantes :

DB: db_id

Base de données : db_id[BULK-OP-DB], qui identifie le verrou de base de données pris par la base de données de sauvegarde.

BASE de données : db_id[BULK-OP-LOG], qui identifie le verrou pris par le journal de sauvegarde pour cette base de données particulière.

APP. Identifie le verrou pris par une ressource d'application. APP est représenté en tant qu’APPLICATION : lock_resource. Par exemple : APP: Formf370f478.

METADATA. Représente les ressources de métadonnées impliquées dans un blocage. Comme METADATA possède de nombreuses sous-ressources, la valeur retournée dépend de la sous-ressource bloquée. Par exemple, METADATA.USER_TYPE retourne user_type_id = *integer_value*. Pour plus d’informations sur les ressources et sous-ressources METADATA, consultez sys.dm_tran_locks (Transact-SQL).

HOBT. Représente un segment de mémoire ou d'arbre B (B-Tree) impliqué dans un blocage.
Non exclusif à cet indicateur de trace. Non exclusif à cet indicateur de trace.

Exemple d’indicateur de trace 1204

L’exemple suivant montre la sortie lorsque l’indicateur de trace 1204 est activé. Dans ce cas, la table du nœud 1 est un segment de mémoire sans index et la table du nœud 2 est un segment de mémoire avec un index non-cluster. La clé d'index du nœud 2 est en cours de mise à jour lorsque le blocage se produit.

Deadlock encountered .... Printing deadlock information  
Wait-for graph  
  
Node:1  
  
RID: 6:1:20789:0               CleanCnt:3 Mode:X Flags: 0x2  
 Grant List 0:  
   Owner:0x0315D6A0 Mode: X          
     Flg:0x0 Ref:0 Life:02000000 SPID:55 ECID:0 XactLockInfo: 0x04D9E27C  
   SPID: 55 ECID: 0 Statement Type: UPDATE Line #: 6  
   Input Buf: Language Event:   
BEGIN TRANSACTION  
   EXEC usp_p2  
 Requested By:   
   ResType:LockOwner Stype:'OR'Xdes:0x03A3DAD0   
     Mode: U SPID:54 BatchID:0 ECID:0 TaskProxy:(0x04976374) Value:0x315d200 Cost:(0/868)  
  
Node:2  
  
KEY: 6:72057594057457664 (350007a4d329) CleanCnt:2 Mode:X Flags: 0x0  
 Grant List 0:  
   Owner:0x0315D140 Mode: X          
     Flg:0x0 Ref:0 Life:02000000 SPID:54 ECID:0 XactLockInfo: 0x03A3DAF4  
   SPID: 54 ECID: 0 Statement Type: UPDATE Line #: 6  
   Input Buf: Language Event:   
     BEGIN TRANSACTION  
       EXEC usp_p1  
 Requested By:   
   ResType:LockOwner Stype:'OR'Xdes:0x04D9E258   
     Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)  
  
Victim Resource Owner:  
 ResType:LockOwner Stype:'OR'Xdes:0x04D9E258   
     Mode: U SPID:55 BatchID:0 ECID:0 TaskProxy:(0x0475E374) Value:0x315d4a0 Cost:(0/380)  

Exemple d’indicateur de trace 1222

L’exemple suivant montre la sortie lorsque l’indicateur de trace 1222 est activé. Dans ce cas, une table est un segment de mémoire sans index et l'autre table un segment de mémoire avec un index non-cluster. Dans la seconde table, la clé d'index est en cours de mise à jour lorsque le blocage se produit.

deadlock-list  
 deadlock victim=process689978  
  process-list  
   process id=process6891f8 taskpriority=0 logused=868   
   waitresource=RID: 6:1:20789:0 waittime=1359 ownerId=310444   
   transactionname=user_transaction   
   lasttranstarted=2022-02-05T11:22:42.733 XDES=0x3a3dad0   
   lockMode=U schedulerid=1 kpid=1952 status=suspended spid=54   
   sbid=0 ecid=0 priority=0 transcount=2   
   lastbatchstarted=2022-02-05T11:22:42.733   
   lastbatchcompleted=2022-02-05T11:22:42.733   
   clientapp=Microsoft SQL Server Management Studio - Query   
   hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user   
   isolationlevel=read committed (2) xactid=310444 currentdb=6   
   lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200  
    executionStack  
     frame procname=AdventureWorks2022.dbo.usp_p1 line=6 stmtstart=202   
     sqlhandle=0x0300060013e6446b027cbb00c69600000100000000000000  
     UPDATE T2 SET COL1 = 3 WHERE COL1 = 1;       
     frame procname=adhoc line=3 stmtstart=44   
     sqlhandle=0x01000600856aa70f503b8104000000000000000000000000  
     EXEC usp_p1       
    inputbuf  
      BEGIN TRANSACTION  
       EXEC usp_p1  
   process id=process689978 taskpriority=0 logused=380   
   waitresource=KEY: 6:72057594057457664 (350007a4d329)     
   waittime=5015 ownerId=310462 transactionname=user_transaction   
   lasttranstarted=2022-02-05T11:22:44.077 XDES=0x4d9e258 lockMode=U   
   schedulerid=1 kpid=3024 status=suspended spid=55 sbid=0 ecid=0   
   priority=0 transcount=2 lastbatchstarted=2022-02-05T11:22:44.077   
   lastbatchcompleted=2022-02-05T11:22:44.077   
   clientapp=Microsoft SQL Server Management Studio - Query   
   hostname=TEST_SERVER hostpid=2216 loginname=DOMAIN\user   
   isolationlevel=read committed (2) xactid=310462 currentdb=6   
   lockTimeout=4294967295 clientoption1=671090784 clientoption2=390200  
    executionStack  
     frame procname=AdventureWorks2022.dbo.usp_p2 line=6 stmtstart=200   
     sqlhandle=0x030006004c0a396c027cbb00c69600000100000000000000  
     UPDATE T1 SET COL1 = 4 WHERE COL1 = 1;       
     frame procname=adhoc line=3 stmtstart=44   
     sqlhandle=0x01000600d688e709b85f8904000000000000000000000000  
     EXEC usp_p2       
    inputbuf  
      BEGIN TRANSACTION  
        EXEC usp_p2      
  resource-list  
   ridlock fileid=1 pageid=20789 dbid=6 objectname=AdventureWorks2022.dbo.T2   
   id=lock3136940 mode=X associatedObjectId=72057594057392128  
    owner-list  
     owner id=process689978 mode=X  
    waiter-list  
     waiter id=process6891f8 mode=U requestType=wait  
   keylock hobtid=72057594057457664 dbid=6 objectname=AdventureWorks2022.dbo.T1   
   indexname=nci_T1_COL1 id=lock3136fc0 mode=X   
   associatedObjectId=72057594057457664  
    owner-list  
     owner id=process6891f8 mode=X  
    waiter-list  
     waiter id=process689978 mode=U requestType=wait  

Evénement Deadlock Graph de SQL Profiler

Il s’agit d’un événement propre à SQL Profiler qui présente une description graphique des tâches et des ressources impliquées dans un interblocage. L’exemple suivant illustre la sortie obtenue à partir de SQL Profiler quand l’événement Deadlock Graph est activé.

Important

Sql Profiler crée des traces qui ont été déconseillées en 2016 et remplacées par des événements étendus. Les événements étendus ont beaucoup moins de surcharge de performances et sont beaucoup plus configurables que les traces. Envisagez d’utiliser l’événement d’interblocage d’événements étendus au lieu de traces.

A screenshot from SSMS of the visual deadlock graph from a SQL trace.

Pour plus d’informations sur l’événement de blocage, consultez Classe d’événements Lock:Deadlock. Pour plus d’informations sur l’exécution du graphe de blocage SQL Profiler, consultez Enregistrer les graphes d’interblocage (SQL Server Profiler).

Il existe des équivalents pour les classes d’événements TRACE SQL dans les événements étendus, consultez Les équivalents d’événements étendus aux classes d’événements trace SQL. Les événements étendus sont recommandés sur les traces SQL.

Gérer les interblocages

Lorsqu’une instance de SQL Server Moteur de base de données choisit une transaction comme victime d’interblocage, elle met fin au lot actuel, restaure la transaction et retourne le message d’erreur 1205 à l’application.

Your transaction (process ID #52) was deadlocked on {lock | communication buffer | thread} resources with another process and has been chosen as the deadlock victim. Rerun your transaction.

Étant donné que toute application qui envoie des requêtes Transact-SQL peut être choisie comme victime du blocage, les applications doivent avoir un gestionnaire d’erreurs qui peut intercepter le message d’erreur 1205. Si une application n'intercepte pas cette erreur, elle peut continuer en ignorant que sa transaction a été annulée, et des erreurs peuvent se produire.

L'implémentation d'un gestionnaire d'erreurs capable d'intercepter le message d'erreur 1205 permet à une application de gérer les situations de blocage et de réagir en conséquence, par exemple en re-soumettant automatiquement la requête impliquée dans le blocage. Cette nouvelle soumission automatique rend la gestion du blocage entièrement transparente pour l'utilisateur.

L'application doit marquer un bref temps d'arrêt avant de soumettre à nouveau la requête. Cela permet à l'autre transaction impliquée dans le blocage d'aboutir et de libérer ses verrous qui faisaient partie du cycle de blocage. Les risques qu'un blocage se reproduise au moment où la requête de nouveau soumise demande ses verrous sont ainsi réduits.

Réduire les interblocages

Même si les interblocages ne peuvent pas être totalement évités, le respect de certaines conventions de codage peut minimiser le risque d'en générer. La réduction des blocages peut augmenter le débit des transactions et réduire la charge du système, car il y a moins de transactions :

  • restaurées, en annulant ce qui a été accompli par la transaction ;
  • resoumises par les applications, car ces transactions ont été restaurées lors du blocage.

Pour réduire le nombre de blocages :

  • Accédez aux objets dans le même ordre.
  • Évitez les interactions utilisateur dans les transactions. - Transactions courtes dans un seul traitement.
  • Utilisez un niveau d'isolement plus faible.
  • Utilisez un niveau d'isolement basé sur le contrôle de version de ligne.
    • Affectez à l’option de base de données READ_COMMITTED_SNAPSHOT la valeur ON pour activer les transactions read-committed afin d’utiliser la gestion de versions de ligne.
    • Utilisez un isolement d’instantané.
  • Utilisez des connexions liées.

Accédez aux objets dans le même ordre

Si toutes les transactions concurrentes accèdent aux objets dans le même ordre, le risque de blocage diminue. Par exemple, si deux transactions simultanées obtiennent un verrou sur la Supplier table, puis sur la Part table, une transaction est bloquée sur la Supplier table jusqu’à ce que l’autre transaction soit terminée. Après la validation ou la restauration de la première transaction, la seconde continue et aucun blocage ne se produit. L'utilisation de procédures stockées pour toutes les modifications de données peut standardiser l'ordre d'accès aux objets.

A diagram of a deadlock.

Évitez les interactions utilisateur dans les transactions

Évitez d'écrire des transactions comprenant une interaction utilisateur, car la vitesse d'exécution des traitements sans intervention de l'utilisateur est beaucoup plus rapide que la vitesse à laquelle un utilisateur doit répondre manuellement aux requêtes telles que la demande d'un paramètre requis par une application. Par exemple, si une transaction attend une entrée de la part de l'utilisateur, et si ce dernier va déjeuner ou rentre chez lui pour le week-end, l'utilisateur empêche la transaction de se terminer. Ceci dégrade les performances du système, car tous les verrous détenus par la transaction ne sont libérés qu'une fois la transaction validée ou restaurée. Même si une situation de blocage ne se produit pas, toutes les autres transactions en attente de la même ressource sont bloquées, en attente de la fin de la transaction.

Transactions courtes dans un seul traitement

Un blocage se produit souvent lorsque plusieurs transactions longues sont exécutées de manière concurrente dans la même base de données. Plus la transaction est longue, plus la durée de détention du verrou exclusif ou de mise à jour est importante, ce qui bloque les autres activités et peut entraîner une situation de blocage.

La création de transactions courtes dans un seul traitement limite les allers-retours sur le réseau en réduisant les délais potentiels d'achèvement de la transaction et de suppression des verrous.

Pour plus d’informations sur les verrous de mise à jour, consultez le guide de verrouillage des transactions et de contrôle de version des lignes.

Utilisez un niveau d’isolement plus faible

Déterminez si une transaction peut être exécutée à un niveau d'isolement faible. L'implémentation de la lecture validée (read committed) permet à une transaction de lire des données lues auparavant (non modifiées) par une autre transaction, sans attendre la fin de la première transaction. L'utilisation d'un niveau d'isolement faible (comme la lecture validée, par exemple) permet de conserver les verrous partagés pendant une durée inférieure à celle d'un niveau d'isolement supérieur (comme le niveau sérialisable) et réduit ainsi la contention de verrouillage.

Niveau d’isolement basé sur le contrôle de version de ligne

Quand l’option de base de données READ_COMMITTED_SNAPSHOT a la valeur ON, une transaction qui s’exécute sous un niveau d’isolation read committed utilise le contrôle de version de ligne plutôt que les verrous partagés lors des opérations de lecture.

Remarque

Certaines applications se basent sur le comportement de verrouillage et de blocage de l'isolement de lecture validée. Avec ces applications, certaines modifications sont nécessaires pour pouvoir activer cette option.

L'isolement d'instantané utilise également le contrôle de version de ligne, qui n'emploie pas de verrous partagés pendant les opérations de lecture. Avant qu’une transaction puisse s’exécuter sous instantané isolation, l’option ALLOW_SNAPSHOT_ISOLATION de base de données doit être définieON.

Implémentez ces niveaux d'isolement pour minimiser les blocages pouvant survenir entre les opérations de lecture et d'écriture.

Utiliser des connexions liées

En utilisant des connexions liées, deux connexions ou plus ouvertes par la même application peuvent coopérer entre elles. Tout verrou acquis par la connexion secondaire apparaît comme s'il avait été posé par la connexion primaire et vice-versa. Ils ne se bloquent donc pas réciproquement.

Arrêter une transaction

Dans un scénario d’interblocage, la transaction victime est automatiquement arrêtée et restaurée. Il n’est pas nécessaire d’arrêter une transaction dans un scénario d’interblocage.

Provoquer un interblocage

Remarque

Cet exemple fonctionne dans l’exemple AdventureWorksLT2019 de base de données avec le schéma et les données par défaut lorsque READ_COMMITTED_SNAPSHOT a été activé. Pour télécharger cet exemple, visitez les exemples de bases de données AdventureWorks.

Pour provoquer un interblocage, vous devez connecter deux sessions à la base de données AdventureWorksLT2019. Nous allons faire référence à ces sessions en tant que session A et session B. Vous pouvez créer ces deux sessions simplement en créant deux fenêtres de requête dans SQL Server Management Studio (SSMS).

Dans la session A, exécutez le code Transact-SQL suivant. Ce code démarre une transaction explicite et exécute une instruction unique qui met à jour la table SalesLT.Product. Pour ce faire, la transaction acquiert un verrou de mise à jour (U) sur une ligne de la table SalesLT.Product qui est convertie en verrou exclusif (X). Nous laissons la transaction ouverte.

BEGIN TRAN

    UPDATE SalesLT.Product SET SellEndDate = SellEndDate + 1
        WHERE Color = 'Red';

À présent, dans la session B, exécutez le code Transact-SQL suivant. Ce code ne démarre pas explicitement une transaction. Il travaille plutôt en mode de validation automatique. Cette instruction met à jour la table SalesLT.ProductDescription. La mise à jour supprime un verrou de mise à jour (U) sur 72 lignes de la table SalesLT.ProductDescription. La requête se joint à d’autres tables, notamment la table SalesLT.Product.

UPDATE SalesLT.ProductDescription SET Description = Description
    FROM SalesLT.ProductDescription as pd
    JOIN SalesLT.ProductModelProductDescription as pmpd on
        pd.ProductDescriptionID = pmpd.ProductDescriptionID
    JOIN SalesLT.ProductModel as pm on
        pmpd.ProductModelID = pm.ProductModelID
    JOIN SalesLT.Product as p on
        pm.ProductModelID=p.ProductModelID
    WHERE p.Color = 'Silver';

Pour effectuer cette mise à jour, la session B a besoin d’un verrou partagé (S) sur les lignes de la table SalesLT.Product, y compris la ligne verrouillée par la session A. La session B sera bloquée sur SalesLT.Product.

Revenez à la session A. Exécutez l’instruction Transact-SQL suivante. Cette opération exécute une deuxième instruction UPDATE dans le cadre de la transaction ouverte.

    UPDATE SalesLT.ProductDescription SET Description = Description
        FROM SalesLT.ProductDescription as pd
        JOIN SalesLT.ProductModelProductDescription as pmpd on
            pd.ProductDescriptionID = pmpd.ProductDescriptionID
        JOIN SalesLT.ProductModel as pm on
            pmpd.ProductModelID = pm.ProductModelID
        JOIN SalesLT.Product as p on
            pm.ProductModelID=p.ProductModelID
        WHERE p.Color = 'Red';

La deuxième instruction de mise à jour de la session A sera bloquée par la session B sur SalesLT.ProductDescription.

La session A et la session B se bloquent mutuellement. Aucune des transactions ne peut se poursuivre, car chacune a besoin d’une ressource verrouillée par l’autre.

Au bout de quelques secondes, le processus de surveillance des interblocages identifie que les transactions de la session A et de la session B se bloquent mutuellement, et qu’aucune ne peut progresser. Un interblocage doit alors se produire, avec la session A comme victime de celui-ci. La session B se termine avec succès. Un message d’erreur apparaît dans la session A avec un texte semblable au suivant :

Msg 1205, Level 13, State 51, Line 7
Transaction (Process ID 51) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Si un blocage n’est pas déclenché, vérifiez que READ_COMMITTED_SNAPSHOT a été activé dans votre exemple de base de données. Les interblocages peuvent se produire dans n’importe quelle configuration de base de données, mais cet exemple nécessite READ_COMMITTED_SNAPSHOT d’être activé.

Vous pouvez ensuite afficher les détails du blocage dans la cible ring_buffer de la system_health session Événements étendus, qui est activée et active par défaut dans SQL Server. Considérez la requête suivante :

WITH cteDeadLocks ([Deadlock_XML]) AS (
  SELECT [Deadlock_XML] = CAST(target_data AS XML) 
  FROM sys.dm_xe_sessions AS xs
  INNER JOIN sys.dm_xe_session_targets AS xst 
  ON xs.[address] = xst.event_session_address
  WHERE xs.[name] = 'system_health'
  AND xst.target_name = 'ring_buffer'
 )
SELECT 
  Deadlock_XML = x.Graph.query('(event/data/value/deadlock)[1]')  
, when_occurred = x.Graph.value('(event/data/value/deadlock/process-list/process/@lastbatchstarted)[1]', 'datetime2(3)') 
, DB = DB_Name(x.Graph.value('(event/data/value/deadlock/process-list/process/@currentdb)[1]', 'int')) --Current database of the first listed process 
FROM (
 SELECT Graph.query('.') AS Graph 
 FROM cteDeadLocks c
 CROSS APPLY c.[Deadlock_XML].nodes('RingBufferTarget/event[@name="xml_deadlock_report"]') AS Deadlock_Report(Graph)
) AS x
ORDER BY when_occurred desc;

Vous pouvez afficher le code XML dans la colonne à l’intérieur Deadlock_XML de SSMS en sélectionnant la cellule qui s’affiche sous forme de lien hypertexte. Enregistrez cette sortie sous la forme d’un .xdl fichier, fermez, puis rouvrez le .xdl fichier dans SSMS pour le graphique d’interblocage visuel. Votre graphique d’interblocage doit ressembler à l’image suivante.

A screenshot of a visual deadlock graph in an .xdl file in SSMS.

Verrouillage optimisé et interblocages

S’applique à : Azure SQL Database

Le verrouillage optimisé a introduit une méthode différente pour verrouiller les mécanismes qui modifient la façon dont les interblocages impliquant des verrous TID exclusifs peuvent être signalés. Sous chaque ressource du rapport d’interblocage <resource-list>, chaque <xactlock> élément signale les ressources sous-jacentes et des informations spécifiques pour les verrous de chaque membre d’un interblocage.

Prenons l’exemple suivant où le verrouillage optimisé est activé :

CREATE TABLE t2 
(a int PRIMARY KEY not null 
,b int null); 

INSERT INTO t2 VALUES (1,10),(2,20),(3,30) 
GO 

Les commandes TSQL suivantes dans deux sessions créent un interblocage sur la table t2:

Dans la session 1 :

--session 1
BEGIN TRAN foo;
UPDATE t2 SET b = b+ 10 WHERE a = 1; 

Dans la session 2 :

--session 2:
BEGIN TRAN bar 
UPDATE t2 SET b = b+ 10 WHERE a = 2; 

Dans la session 1 :

--session 1:
UPDATE t2 SET b = b + 100 WHERE a = 2; 

Dans la session 2 :

--session 2:
UPDATE t2 SET b = b + 20 WHERE a = 1; 

Ce scénario d’instructions concurrentes UPDATE entraîne un blocage. Dans ce cas, une ressource de verrouillage de clés, où chaque session contient un verrou X sur son propre TID et attend le verrou S sur l’autre TID, ce qui entraîne un blocage. Le code XML suivant, capturé en tant que rapport d’interblocage, contient des éléments et des attributs spécifiques au verrouillage optimisé :

A screenshot of the XML of a deadlock report showing the UnderlyingResource nodes and keylock nodes specific to optimized locking.

Contenu associé