Pourquoi cette requête provoque-t-elle un blocage?

11

Pourquoi cette requête provoque-t-elle un blocage?

UPDATE TOP(1) system_Queue SET
  [StatusID] = 2,
  @ID = InternalID
WHERE InternalID IN (
    SELECT TOP 1 
      InternalID FROM system_Queue
    WHERE IsOutGoing = @IsOutGoing AND StatusID = 1
ORDER BY MessageID ASC, InternalID ASC)

Graphique de blocage ajouté:

<keylock hobtid="72057594236436480" dbid="9" objectname="Z.dbo.system_Queue" indexname="PK_system_Queue" id="lock5b25cc80" mode="X" associatedObjectId="72057594236436480">
    <owner-list>
     <owner id="processc6fe40" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc7b8e8" mode="S" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594405453824" dbid="9" objectname="Z.dbo.system_Queue" indexname="IX_system_Queue_DirectionByStatus" id="lock48cf3180" mode="S" associatedObjectId="72057594405453824">
    <owner-list>
     <owner id="processc7b8e8" mode="S"/>
    </owner-list>
    <waiter-list>
     <waiter id="processc6fe40" mode="X" requestType="wait"/>
    </waiter-list>
   </keylock>

AJOUTÉE:

Merci Sankar pour cet article qui propose des solutions pour éviter ce type de blocage:

  • éliminer les colonnes inutiles de la projection du lecteur pour qu'il n'ait pas à rechercher l'index clusterisé
  • ajouter les colonnes requises en tant que colonnes contenues à l'index non clusterisé pour couvrir l'index, encore une fois afin que le lecteur n'ait pas à rechercher l'index clusterisé
  • éviter les mises à jour qui doivent maintenir l'index non clusterisé
garik
la source
quelle version de quelle plateforme db utilisez-vous? quel est le niveau d'isolement trx (ou simultanéité) par défaut? Quels index existent actuellement sur la table system_Queue?
SQLRockstar
Ajout d'une partie @SQLRockstar du graphique de blocage, SQL Server 2008
Garik
@SQLRockstar IX_system_Queue_DirectionByStatus index par IsOutGoing et StatusID.
garik

Réponses:

13

Il me semble que vous essayez de faire un SELECT et un UPDATE dans la même instruction et sur la même table.

Le SELECT détient un verrou partagé sur les valeurs à l'intérieur de l'index IX_system_Queue_DirectionByStatus, et l'UPDATE a besoin que ces verrous soient libérés avant qu'il puisse obtenir son verrou exclusif qui mettra à jour la clé primaire (qui, je suppose, est en cluster et fait également partie de la Valeur de la clé IX_system_Queue_DirectionByStatus).

Quoi qu'il en soit, je suppose que cette requête ne réussirait que dans les rares cas où les valeurs d'index qu'elle sélectionne et met à jour ne sont pas en conflit. Est-ce un blocage à chaque fois que vous exécutez (je suppose que ce le serait).

Voici un lien qui explique les blocages plus en détail: http://sqlblog.com/blogs/jonathan_kehayias/archive/2008/07/30/the-anatomy-of-a-deadlock.aspx

SQLRockstar
la source
Bingo! Je vous remercie. C'était une situation vraiment étrange pour une impasse que j'ai jamais vue. Merci de votre réponse.
garik