Gibt es eine Möglichkeit, den Deadlock zu verhindern, während dieselben Abfragen beibehalten werden?
Das Deadlock-Diagramm zeigt, dass es sich bei diesem bestimmten Deadlock um einen Conversion-Deadlock handelt, der mit einer Lesezeichensuche (in diesem Fall einer RID-Suche) verknüpft ist:
Wie die Frage feststellt, besteht das allgemeine Deadlock-Risiko, da die Abfragen möglicherweise inkompatible Sperren für dieselben Ressourcen in unterschiedlichen Reihenfolgen erhalten. Die SELECT
Abfrage muss aufgrund der RID-Suche auf den Index vor der Tabelle zugreifen, während die UPDATE
Abfrage zuerst die Tabelle und dann den Index ändert.
Um den Deadlock zu beseitigen, muss einer der Deadlock-Bestandteile entfernt werden. Das Folgende sind die Hauptoptionen:
- Vermeiden Sie die RID-Suche, indem Sie den nicht gruppierten Index abdecken. Dies ist in Ihrem Fall wahrscheinlich nicht praktikabel, da die
SELECT
Abfrage 26 Spalten zurückgibt.
- Vermeiden Sie die RID-Suche, indem Sie einen Clustered-Index erstellen. Dazu müsste ein Clustered-Index für die Spalte erstellt werden
Proposal
. Dies ist eine Überlegung wert, obwohl es den Anschein hat, dass diese Spalte vom Typ ist uniqueidentifier
, was in Abhängigkeit von weiter gefassten Themen eine gute Wahl für einen Clustered-Index sein kann oder nicht.
- Vermeiden Sie es, beim Lesen gemeinsame Sperren zu verwenden, indem Sie die Datenbankoptionen
READ_COMMITTED_SNAPSHOT
oder aktivieren SNAPSHOT
. Dies würde sorgfältige Tests erfordern, insbesondere in Bezug auf das Verhalten der eingebauten Blockierung. Der Auslösecode muss auch getestet werden, um sicherzustellen, dass die Logik korrekt funktioniert.
- Vermeiden Sie es, beim Lesen gemeinsame Sperren zu verwenden, indem Sie die
READ UNCOMMITTED
Isolationsstufe für die SELECT
Abfrage verwenden. Es gelten alle üblichen Vorsichtsmaßnahmen.
- Vermeiden Sie die gleichzeitige Ausführung der beiden fraglichen Abfragen, indem Sie eine exklusive Anwendungssperre verwenden (siehe sp_getapplock ).
- Verwenden Sie Hinweise zur Tabellensperre, um Parallelität zu vermeiden. Dies ist ein größerer Hammer als Option 5, da sich dies möglicherweise auf andere Anfragen auswirkt, nicht nur auf die beiden in der Frage identifizierten.
Kann ich in der Update-Transaktion vor dem Update irgendwie eine X-Sperre für den Index durchführen, um sicherzustellen, dass der Zugriff auf die Tabelle und den Index in derselben Reihenfolge erfolgt?
Sie können dies versuchen, indem Sie das Update in eine explizite Transaktion einschließen und vor dem Update SELECT
einen XLOCK
Hinweis auf den nicht gruppierten Indexwert ausführen. Dies setzt voraus, dass Sie mit Sicherheit wissen, wie hoch der aktuelle Wert im nicht gruppierten Index ist, den Ausführungsplan korrekt ausführen und alle Nebenwirkungen dieser zusätzlichen Sperre korrekt antizipieren. Es hängt auch davon ab, dass die Locking-Engine nicht intelligent genug ist, um zu verhindern, dass das Schloss geschlossen wird, wenn es als redundant eingestuft wird .
Kurz gesagt, obwohl dies im Prinzip machbar ist, empfehle ich es nicht. Es ist zu leicht, etwas zu verpassen oder sich kreativ auszutricksen. Wenn Sie diese Deadlocks wirklich vermeiden müssen (anstatt sie nur zu erkennen und erneut zu versuchen), empfehle ich Ihnen, sich stattdessen die oben aufgeführten allgemeineren Lösungen anzusehen.
Ich habe ein ähnliches Problem, das gelegentlich auftritt, und hier ist der Ansatz, den ich nehme.
set deadlock priority low;
die Auswahl. Dadurch wird diese Abfrage zum Deadlock-Opfer, wenn ein Deadlock auftritt.Hinweis: Wenn Sie
select
Teil einer expliziten Transaktion mit mehreren Anweisungen sind, müssen Sie sicherstellen, dass Sie die gesamte Transaktion wiederholen und nicht nur die fehlgeschlagene Anweisung. Andernfalls können unerwartete Ergebnisse auftreten. Wenn dies ein einziges ist ,select
dann sind Sie in Ordnung, aber wenn es Aussage istx
vonn
innerhalb einer Transaktion, dann nur sicherstellen , wiederholen Sie allen
Anweisungen während der Wiederholung.quelle