Warum verursacht diese Abfrage einen Deadlock?

11

Warum verursacht diese Abfrage einen Deadlock?

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)

Deadlock-Grafik hinzugefügt:

<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>

HINZUGEFÜGT:

Vielen Dank an Sankar für den Artikel, der Lösungen zur Vermeidung dieser Art von Deadlock enthält:

  • Entfernen Sie unnötige Spalten aus der Projektion des Lesers, damit er den Clustered-Index nicht nachschlagen muss
  • Fügen Sie dem nicht gruppierten Index die erforderlichen Spalten als enthaltene Spalten hinzu, damit der Index abgedeckt wird, damit der Leser den gruppierten Index nicht nachschlagen muss
  • Vermeiden Sie Aktualisierungen, bei denen der nicht gruppierte Index beibehalten werden muss
garik
quelle
Welche Version von welcher Datenbankplattform verwenden Sie? Was ist die Standard-Trx-Isolationsstufe (oder Parallelitätsstufe)? Welche Indizes sind derzeit in der Tabelle system_Queue vorhanden?
SQLRockstar
@ SQLRockstar Teil des Deadlock-Diagramms hinzugefügt, SQL Server 2008
Garik
@SQLRockstar IX_system_Queue_DirectionByStatus Index von IsOutGoing und StatusID.
Garik

Antworten:

13

Es sieht für mich so aus, als würden Sie versuchen, ein SELECT und ein UPDATE in derselben Anweisung und in derselben Tabelle auszuführen.

Das SELECT hält eine gemeinsame Sperre für die Werte im IX_system_Queue_DirectionByStatus-Index, und das UPDATE muss diese Sperren freigeben, bevor es seine exklusive Sperre erhält, die den Primärschlüssel aktualisiert (der vermutlich gruppiert ist und auch Teil des IX_system_Queue_DirectionByStatus-Schlüsselwert).

Ich vermute jedenfalls, dass diese Abfrage nur dann erfolgreich ist, wenn die ausgewählten und aktualisierten Indexwerte nicht in Konflikt stehen. Ist es bei jeder Ausführung ein Deadlock? (Ich gehe davon aus, dass dies der Fall ist.)

Hier ist ein Link, der Deadlocks ausführlicher erklärt: http://sqlblog.com/blogs/jonathan_kehayias/archive/2008/07/30/the-anatomy-of-a-deadlock.aspx

SQLRockstar
quelle
Bingo! Vielen Dank. Es war wirklich eine seltsame Situation für einen Deadlock, den ich je gesehen habe. Danke für die Antwort.
Garik