Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Die Anatomie von SQL Server-Deadlocks und die besten Möglichkeiten, sie zu vermeiden

Datenbankfachleute werden routinemäßig mit Datenbankleistungsproblemen wie unsachgemäßer Indizierung und schlecht geschriebenem Code in Produktions-SQL-Instanzen konfrontiert. Angenommen, Sie haben eine Transaktion aktualisiert und SQL Server hat die folgende Deadlock-Meldung gemeldet. Für DBAs, die gerade erst anfangen, könnte dies ein Schock sein.

In diesem Artikel untersuchen wir SQL Server-Deadlocks und die besten Möglichkeiten, sie zu vermeiden.

Was ist ein SQL Server-Deadlock?

SQL Server ist eine stark transaktionale Datenbank. Angenommen, Sie unterstützen die Datenbank für ein Online-Shopping-Portal, auf dem Sie rund um die Uhr neue Bestellungen von Kunden erhalten. Wahrscheinlich führen mehrere Benutzer gleichzeitig dieselbe Aktivität aus. In diesem Fall sollte Ihre Datenbank den Eigenschaften Atomicity, Consistency, Isolation, Durability (ACID) folgen, um konsistent und zuverlässig zu sein und die Datenintegrität zu schützen.

Das folgende Bild beschreibt die ACID-Eigenschaften in einer relationalen Datenbank.

Um den ACID-Eigenschaften zu folgen, verwendet SQL Server Sperrmechanismen, Einschränkungen und Write-Ahead-Protokollierung. Zu den verschiedenen Sperrtypen gehören:exklusive Sperre (X), gemeinsame Sperre (S), Aktualisierungssperre (U), Absichtssperre (I), Schemasperre (SCH) und Massenaktualisierungssperre (BU). Diese Sperren können auf Schlüssel-, Tabellen-, Zeilen-, Seiten- und Datenbankebene erworben werden.

Angenommen, Sie haben zwei Benutzer, John und Peter, die mit der Kundendatenbank verbunden sind.

  • John möchte die Datensätze für den Kunden mit [Kunden-ID] 1 aktualisieren.
  • Gleichzeitig möchte Peter den Wert für den Kunden mit [Kunden-ID] 1 abrufen.

In diesem Fall verwendet SQL Server die folgenden Sperren für John und Peter.

Sperren für John

  • Die Kundentabelle und die Seite, die den Datensatz enthalten, werden mit einer Absichts-Exklusivsperre (IX) gesperrt.
  • Es benötigt außerdem eine exklusive (X) Sperre für die Zeile, die John aktualisieren möchte. Es verhindert, dass andere Benutzer die Zeilendaten ändern, bis Prozess A seine Sperre freigibt.

Sperren für Peter

  • Es erwirbt eine Intent Shared (IS)-Sperre für die Kundentabelle und die Seite, die den Datensatz gemäß der Where-Klausel enthält.
  • Es wird versucht, eine gemeinsame Sperre zu verwenden, um die Zeile zu lesen. Diese Zeile hat bereits eine exklusive Sperre für John.

In diesem Fall muss Peter warten, bis John seine Arbeit beendet und die exklusive Sperre freigibt. Diese Situation wird als Blockierung bezeichnet.

Angenommen, in einem anderen Szenario haben John und Peter die folgenden Sperren.

  • John hat eine exklusive Sperre für die Kundentabelle für die Kunden-ID 1.
  • Peter hat eine exklusive Sperre für die Orders-Tabelle für die Kunden-ID 1.
  • John benötigt eine exklusive Sperre für die Auftragstabelle, um seine Transaktion abzuschließen. Peter hat bereits eine exklusive Sperre für die Auftragstabelle.
  • Peter benötigt eine exklusive Sperre für die Kundentabelle, um seine Transaktion abzuschließen. John hat bereits eine exklusive Sperre für die Kundentabelle.

In diesem Fall kann keine der Transaktionen fortgesetzt werden, da jede Transaktion eine Ressource erfordert, die von der anderen Transaktion gehalten wird. Diese Situation wird als SQL Server-Deadlock bezeichnet.

Deadlock-Überwachungsmechanismen von SQL Server

SQL Server überwacht Deadlock-Situationen regelmäßig mithilfe des Deadlock-Monitor-Threads. Dadurch werden die an einem Deadlock beteiligten Prozesse überprüft und festgestellt, ob eine Sitzung einem Deadlock zum Opfer gefallen ist. Es verwendet einen internen Mechanismus, um den Deadlock-Opferprozess zu identifizieren. Standardmäßig wird die Transaktion mit den geringsten für das Rollback erforderlichen Ressourcen als Opfer betrachtet.

SQL Server beendet die betroffene Sitzung, damit eine andere Sitzung die erforderliche Sperre erwerben kann, um ihre Transaktion abzuschließen. Standardmäßig überprüft SQL Server die Deadlock-Situation alle 5 Sekunden mit dem Deadlock-Monitor. Wenn es einen Deadlock erkennt, kann es die Frequenz je nach Auftreten des Deadlocks von 5 Sekunden auf 100 Millisekunden reduzieren. Es setzt den Überwachungs-Thread erneut auf 5 Sekunden zurück, wenn keine häufigen Deadlocks auftreten.

Sobald der SQL Server einen Prozess als Deadlock-Opfer beendet, erhalten Sie die folgende Meldung. In dieser Sitzung war Prozess-ID 69 ein Deadlock-Opfer.

Die Auswirkungen der Verwendung von Deadlock-Prioritätsanweisungen für SQL Server

Standardmäßig markiert SQL Server die Transaktion mit dem kostengünstigsten Rollback als Deadlock-Opfer. Benutzer können die Deadlock-Priorität in einer Transaktion mit der DEADLOCK_PRIORITY-Anweisung festlegen.

SET DEADLOCK_PRIORITY

Es verwendet die folgenden Argumente:

  • Niedrig:Entspricht Deadlock-Priorität -5
  • Normal:Dies ist die Standard-Deadlock-Priorität 0
  • Hoch:Dies ist die höchste Deadlock-Priorität 5.

Wir können auch numerische Werte für die Deadlock-Priorität von -10 bis 10 (insgesamt 21 Werte) festlegen.

Sehen wir uns einige Beispiele für Deadlock-Prioritätsanweisungen an.

Beispiel 1:

Sitzung 1 mit Deadlock-Priorität:Normal (0)> Sitzung 2 mit Deadlock-Priorität:Niedrig (-5)

Deadlock-Opfer:  Sitzung 2

Beispiel 2:

Sitzung 1 mit Deadlock-Priorität:Normal (0)

Deadlock-Opfer:  Sitzung 1

Beispiel 3

Sitzung 1 mit Deadlock-Priorität:-3> Sitzung 2 mit Deadlock-Priorität:-7

Beispiel 4:

Sitzung 1 mit Deadlock-Priorität:-5

Deadlock-Opfer:  Sitzung 1

SQL Server-Deadlocks mithilfe von Deadlock-Diagrammen

Ein Deadlock-Diagramm ist eine visuelle Darstellung der Deadlock-Prozesse, ihrer Sperren und des Deadlock-Opfers. Wir können die Trace-Flags 1204 und 1222 aktivieren, um Deadlock-Detailinformationen in einem XML- und Grafikformat zu erfassen. Wir können das standardmäßige erweiterte system_health-Ereignis verwenden, um die Deadlock-Details abzurufen. Ein Deadlock-Diagramm lässt sich schnell und einfach interpretieren. Lassen Sie uns eine Deadlock-Bedingung simulieren und das entsprechende Deadlock-Diagramm anzeigen.

Für diese Demonstration haben wir die Tabelle Customer and Orders erstellt und einige Beispieldatensätze eingefügt.

CREATE TABLE Customer (ID INT IDENTITY(1,1), CustomerName VARCHAR(20)) GO CREATE TABLE Orders (OrderID INT IDENTITY(1,1), ProductName VARCHAR(50)) GO INSERT INTO Customer(CustomerName) VALUES ('Rajendra') Go 100 S INSERT INTO Orders(ProductName) VALUES ('Laptop') Go 100

Dann haben wir ein neues Abfragefenster geöffnet und das Trace-Flag global aktiviert.

DBCC-Traceon(1222,-1)

Nachdem wir das Deadlock-Trace-Flag aktiviert hatten, starteten wir zwei Sitzungen und führten die Abfrage in der folgenden Reihenfolge aus:

  • Die erste Sitzung startet eine Transaktion, um die Kundentabelle für Kunden-ID 1 zu aktualisieren.
  • Die zweite Sitzung startet eine Transaktion zum Aktualisieren der Bestelltabelle für die Bestell-ID 10.
  • Die erste Sitzung versucht, die Bestelltabelle für dieselbe Bestell-ID 10 zu aktualisieren. Die zweite Sitzung sperrt diese Zeile bereits. Sitzung 1 ist aufgrund der Sperren von Sitzung 2 blockiert.
  • Nun möchten wir für Sitzung 2 die Kundentabelle für Kunden-ID 1 aktualisieren. Dies erzeugt eine Deadlock-Situation, in der beide Sitzungen ID 63 und ID 65 nicht fortfahren können.

In diesem Beispiel wählt SQL Server ein Deadlock-Opfer (Sitzungs-ID 65) und beendet die Transaktion. Lassen Sie uns das Deadlock-Diagramm aus der erweiterten Ereignissitzung system_health abrufen.

SELECT XEvent.query('(event/data/value/deadlock)[1]') AS DeadlockGraph FROM ( SELECT XEvent.query('.') AS XEvent FROM ( SELECT CAST(target_data AS XML) AS TargetData FROM sys.dm_xe_session_targets st INNER JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address WHERE s.NAME = ‘system_health’ AND st.target_name = ‘ring_buffer’ ) AS Data CROSS APPLY TargetData.nodes('RingBufferTarget/event[@name="xml_deadlock_report"] ') AS XEventData(XEvent) ) AS source;

Diese Abfrage gibt uns ein Deadlock-XML, das einen erfahrenen DBA erfordert, um die Informationen zu interpretieren.

Wir speichern diese Deadlock-XML mit der Erweiterung .XDL und wenn wir die XDL-Datei in SSMS öffnen, erhalten wir das unten gezeigte Deadlock-Diagramm.

Dieses Deadlock-Diagramm enthält die folgenden Informationen:

  • Prozessknoten:  Im Oval erhalten Sie prozessbezogene Informationen.
  • Ressourcenknoten:  Ressourcenknoten (quadratische Kästchen) liefern zusammen mit den Sperren Informationen über die an den Transaktionen beteiligten Objekte. In diesem Beispiel zeigt es RID-Sperren, weil wir keine Indizes für beide Tabellen haben.
  • Kanten:  Eine Kante verbindet den Prozessknoten und den Ressourcenknoten. Es zeigt den Ressourceneigentümer und den Anforderungssperrmodus.

Es stellt ein Deadlock-Opfer dar, indem das Oval im Deadlock-Diagramm durchgestrichen wird.

Sie können SQL Server-Deadlock-Informationen auf folgende Weise erfassen:

  • SQL Server-Profiler
  • Erweiterte SQL Server-Ereignisse
  • SQL Server-Fehlerprotokolle
  • Standardablaufverfolgungen in SQL Server

5 Arten von Deadlocks in SQL Server

1) Lesezeichensuche-Deadlock

Die Lesezeichensuche ist ein häufig anzutreffender Deadlock in SQL Server. Es tritt aufgrund eines Konflikts zwischen der Select-Anweisung und den DML-Anweisungen (insert, update und delete) auf. Normalerweise wählt SQL Server die select-Anweisung als Opfer eines Deadlocks, da sie keine Datenänderungen verursacht und das Rollback schnell erfolgt. Um die Lesezeichensuche zu vermeiden, können Sie einen abdeckenden Index verwenden. Sie können auch einen NOLOCK-Abfragehinweis in den Select-Anweisungen verwenden, aber er liest nicht festgeschriebene Daten.

2) Range-Scan-Deadlock

Manchmal verwenden wir eine SERIALIZABLE-Isolationsstufe auf Serverebene oder Sitzungsebene. Es ist eine restriktive Isolationsstufe für die Parallelitätssteuerung und kann Bereichs-Scan-Sperren anstelle von Sperren auf Seiten- oder Zeilenebene erstellen. Auf der Isolationsstufe SERIALIZABLE können Benutzer keine Daten lesen, wenn sie geändert wurden, aber darauf warten, in einer Transaktion festgeschrieben zu werden. Wenn eine Transaktion Daten liest, kann eine andere Transaktion sie nicht ändern. Es bietet die niedrigste Parallelität, daher sollten wir diese Isolationsstufe in bestimmten Anwendungsanforderungen verwenden.

3) Deadlock für kaskadierende Einschränkungen

SQL Server verwendet die Eltern-Kind-Beziehung zwischen Tabellen mithilfe der Fremdschlüsseleinschränkungen. Wenn wir in diesem Szenario einen Datensatz aus der übergeordneten Tabelle aktualisieren oder löschen, werden die erforderlichen Sperren für die untergeordnete Tabelle benötigt, um verwaiste Datensätze zu verhindern. Um diese Deadlocks zu beseitigen, sollten Sie immer zuerst Daten in einer untergeordneten Tabelle ändern, gefolgt von den übergeordneten Daten. Sie können auch direkt mit der übergeordneten Tabelle arbeiten, indem Sie die Optionen DELETE CASCADE oder UPDATE CASCADE verwenden. Sie sollten auch geeignete Indizes für die Fremdschlüsselspalten erstellen.

4) Intra-Abfrage-Parallelismus-Deadlock

Sobald ein Nutzer eine Abfrage an die SQL-Abfrage-Engine sendet, erstellt der Abfrageoptimierer einen optimierten Ausführungsplan. Abhängig von den Abfragekosten, dem maximalen Parallelitätsgrad (MAXDOP) und dem Kostenschwellenwert für Parallelität kann die Abfrage in serieller oder paralleler Reihenfolge ausgeführt werden.

In einem Parallelmodus weist SQL Server mehrere Threads zu. Manchmal beginnen diese Threads bei einer großen Abfrage in einem Parallelitätsmodus, sich gegenseitig zu blockieren. Schließlich wandelt es sich in Deadlocks um. In diesem Fall müssen Sie den Ausführungsplan und Ihren MAXDOP- und Kostenschwellenwert für Parallelitätskonfigurationen überprüfen. Sie können MAXDOP auch auf Sitzungsebene angeben, um das Deadlock-Szenario zu beheben.

5) Objektreihenfolge-Deadlock umkehren

Bei dieser Art von Deadlock greifen mehrere Transaktionen in T-SQL in einer anderen Reihenfolge auf Objekte zu. Dies bewirkt eine Blockierung zwischen den Ressourcen für jede Sitzung und wandelt sie in einen Deadlock um. Sie möchten immer in einer logischen Reihenfolge auf Objekte zugreifen, damit es nicht zu einer Deadlock-Situation kommt.

Nützliche Methoden zur Vermeidung und Minimierung von SQL Server-Deadlocks

  • Versuchen Sie, Transaktionen kurz zu halten; dies vermeidet das Halten von Sperren in einer Transaktion über einen langen Zeitraum.
  • Greifen Sie in mehreren Transaktionen auf ähnliche logische Weise auf Objekte zu.
  • Erstellen Sie einen abdeckenden Index, um die Möglichkeit eines Deadlocks zu reduzieren.
  • Erstellen Sie Indizes, um die Fremdschlüsselspalten abzugleichen. Auf diese Weise können Sie Deadlocks aufgrund kaskadierender referenzieller Integrität beseitigen.
  • Legen Sie Deadlock-Prioritäten mit der Session-Variable SET DEADLOCK_PRIORITY fest. Wenn Sie die Deadlock-Priorität festlegen, beendet SQL Server die Sitzung mit der niedrigsten Deadlock-Priorität.
  • Verwenden Sie die Fehlerbehandlung mit den Try-Catch-Blöcken. Sie können den Deadlock-Fehler abfangen und die Transaktion im Falle eines Deadlock-Opfers erneut ausführen.
  • Ändern Sie die Isolationsstufe zu READ COMMITTED SNAPSHOT ISOLATION oder SNAPSHOT ISOLATION. Dadurch wird der Sperrmechanismus von SQL Server geändert. Allerdings sollten Sie beim Ändern der Isolationsstufe vorsichtig sein, da sich dies negativ auf andere Abfragen auswirken kann.

Überlegungen zu SQL Server-Deadlocks

Deadlocks sind ein natürlicher Mechanismus in SQL Server, um zu vermeiden, dass die Sitzung Sperren hält und auf andere Ressourcen wartet. Sie sollten Deadlock-Abfragen erfassen und optimieren, damit sie nicht miteinander in Konflikt geraten. Es ist wichtig, die Sperre für einen kurzen Zeitraum zu erfassen und freizugeben, damit andere Abfragen sie effektiv nutzen können.

SQL Server-Deadlocks treten auf, und obwohl SQL Server Deadlock-Situationen intern handhabt, sollten Sie versuchen, sie nach Möglichkeit zu minimieren. Deadlocks lassen sich am besten beseitigen, indem Sie einen Index erstellen, Änderungen am Anwendungscode anwenden oder die Ressourcen in einem Deadlock-Diagramm sorgfältig untersuchen. Weitere Tipps zur Vermeidung von SQL-Deadlocks finden Sie in unserem Beitrag: Vermeidung von SQL-Deadlocks durch Abfrageoptimierung.