Deadlocks aus Logs analysieren: Ursachen praezise rekonstruieren
AI generated
SELECT
JOIN
SQL · Deadlocks · InnoDB · PostgreSQL
Deadlocks aus Logs analysieren
vom kryptischen Eintrag zur konkreten Ursache

Ein Deadlock-Log-Eintrag wirkt beim ersten Lesen wie kryptischer Rauschtext, enthaelt aber alle Informationen, um die Ursache exakt zu rekonstruieren. Wer Deadlocks aus Logs systematisch analysiert, statt sie als seltenen Zufall abzutun, findet die zugrunde liegende Sperr-Reihenfolge im Code und behebt sie dauerhaft statt nur den naechsten Reconnect abzuwarten.

18 Min. Lesezeit SHOW ENGINE INNODB STATUS · PostgreSQL Log · Sperr-Reihenfolge MySQL · PostgreSQL · InnoDB

1. Warum Deadlocks nie wirklich zufaellig sind

Ein Deadlock entsteht, wenn zwei oder mehr Transaktionen sich gegenseitig auf Sperren warten, die die jeweils andere Transaktion haelt, sodass keine der beteiligten Transaktionen jemals fortfahren kann. Die Datenbank erkennt diesen Zustand und bricht eine der Transaktionen zwangsweise ab, um den Stillstand aufzuloesen. Aus Anwendungssicht wirkt das oft wie ein seltener, kaum reproduzierbarer Zufall, tatsaechlich aber steckt hinter fast jedem Deadlock eine deterministische, wiederholbare Sperr-Reihenfolge im Code.

Genau diese Determinismus macht es lohnend, Deadlocks aus Logs zu analysieren, statt sie als unvermeidbares Grundrauschen zu akzeptieren. Ein Deadlock-Log-Eintrag enthaelt die vollstaendigen SQL-Statements beider beteiligten Transaktionen, die exakt gehaltenen und angeforderten Sperren und die Reihenfolge, in der sie erworben wurden. Wer diese Informationen richtig liest, findet fast immer eine konkrete Codestelle, an der zwei Operationen Ressourcen in unterschiedlicher Reihenfolge sperren.

Der haeufigste Fehler im Umgang mit Deadlocks ist, sie ausschliesslich mit Retry-Logik im Anwendungscode zu behandeln, ohne die zugrunde liegende Ursache zu untersuchen. Retry-Logik ist sinnvoll als Sicherheitsnetz, ersetzt aber nicht die eigentliche Analyse. Wer Deadlocks aus Logs analysiert, findet die eigentliche Wurzel und kann sie dauerhaft beheben, statt bei wachsender Last mit immer mehr Deadlocks pro Minute zu leben.

2. Den InnoDB-Deadlock-Output aktivieren und lesen

MySQL und MariaDB mit InnoDB protokollieren den zuletzt aufgetretenen Deadlock standardmaessig im internen Statuspuffer, abrufbar ueber SHOW ENGINE INNODB STATUS im Abschnitt LATEST DETECTED DEADLOCK. Das Problem: Nur der jeweils letzte Deadlock wird vorgehalten, ein frueherer Vorfall ist ueberschrieben, sobald ein neuer auftritt. Fuer systematische Analyse ist deshalb innodb_print_all_deadlocks unverzichtbar, eine Einstellung, die jeden Deadlock zusaetzlich ins allgemeine Error-Log schreibt.

Aktiviert man diese Option, landen alle Deadlocks dauerhaft im Error-Log und koennen mit Standard-Log-Analyse-Werkzeugen ausgewertet werden, statt bei jedem Vorfall manuell SHOW ENGINE INNODB STATUS im richtigen Moment abzufragen. Diese eine Konfigurationsaenderung ist der wichtigste erste Schritt, um Deadlocks aus Logs systematisch zu analysieren, statt auf den naechsten zufaelligen Vorfall zu warten.


-- Alle Deadlocks dauerhaft ins Error-Log schreiben (MySQL 5.6.15+)
SET GLOBAL innodb_print_all_deadlocks = ON;

-- Letzten Deadlock manuell abrufen (nur der neueste ist verfuegbar)
SHOW ENGINE INNODB STATUS\G

-- Ausschnitt eines typischen Deadlock-Eintrags im Error-Log:
-- 2026-07-29T10:14:22 0x7f2a3c001700 InnoDB: transactions deadlock detected, dumping detailed information.
-- *** (1) TRANSACTION:
-- TRANSACTION 421839201, ACTIVE 2 sec starting index read
-- mysql tables in use 1, locked 1
-- LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s)
-- MySQL thread id 812, OS thread handle, query id 91234 checkout update
-- UPDATE orders SET status = 'paid' WHERE id = 4821
-- *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
-- RECORD LOCKS space id 45 page no 12 n bits 80 index PRIMARY of table `shop`.`orders`
-- *** (2) TRANSACTION:
-- TRANSACTION 421839205, ACTIVE 1 sec starting index read
-- UPDATE inventory SET stock = stock - 1 WHERE order_id = 4821
-- *** (2) HOLDS THE LOCK(S):
-- RECORD LOCKS space id 45 page no 12 n bits 80 index PRIMARY of table `shop`.`orders`
-- *** WE ROLL BACK TRANSACTION (1)

3. Struktur des InnoDB-Deadlock-Eintrags entschluesseln

Der InnoDB-Deadlock-Eintrag folgt einem festen Muster mit zwei nummerierten Transaktions-Bloecken, (1) und (2). Jeder Block zeigt zuerst die aktive Query der Transaktion, danach entweder WAITING FOR THIS LOCK TO BE GRANTED (die Sperre, auf die gewartet wird) oder HOLDS THE LOCK(S) (die Sperre, die bereits gehalten wird). Die entscheidende Zeile am Ende, WE ROLL BACK TRANSACTION, zeigt, welche der beiden Transaktionen die Datenbank zwangsweise beendet hat.

Um Deadlocks aus Logs zu analysieren, muss man die beiden Blocke gegenueberstellen: Transaktion (1) haelt Sperre A und wartet auf Sperre B. Transaktion (2) haelt Sperre B und wartet auf Sperre A. Genau dieses Kreuzmuster ist die Definition eines Deadlocks. Im Beispiel oben sperrt die erste Transaktion zuerst die Bestellzeile und wartet dann auf den Lagerbestand, waehrend die zweite Transaktion die umgekehrte Reihenfolge verwendet, eine klassische inkonsistente Sperr-Reihenfolge zwischen zwei Tabellen.

4. PostgreSQL-Deadlock-Log lesen

PostgreSQL protokolliert Deadlocks automatisch im Server-Log, ohne dass eine separate Einstellung wie bei MySQL noetig waere, solange das normale Logging aktiv ist. Ein PostgreSQL-Deadlock-Eintrag beginnt mit ERROR: deadlock detected, gefolgt von einem DETAIL-Abschnitt, der die Prozess-IDs beider beteiligten Sessions, die jeweils angeforderten Sperren und den CONTEXT mit dem vollstaendigen SQL-Statement zeigt.

Der grosse Vorteil gegenueber InnoDB: PostgreSQL protokolliert jeden Deadlock automatisch dauerhaft ohne zusaetzliche Konfiguration, da es kein Ueberschreibungsproblem wie bei SHOW ENGINE INNODB STATUS gibt. Wer Deadlocks aus Logs analysiert, findet in PostgreSQL deshalb tendenziell eine vollstaendigere Historie ohne vorherige Einrichtungsschritte.


-- Typischer PostgreSQL-Deadlock-Eintrag im Server-Log:
-- ERROR:  deadlock detected
-- DETAIL:  Process 18234 waits for ShareLock on transaction 891234;
--          blocked by process 18240.
--          Process 18240 waits for ShareLock on transaction 891230;
--          blocked by process 18234.
-- HINT:  See server log for query details.
-- CONTEXT:  while updating tuple (0,5) in relation "orders"
-- STATEMENT:  UPDATE orders SET status = 'paid' WHERE id = 4821;

-- log_lock_waits ergaenzend aktivieren, um Vorlaufzeit vor dem Deadlock zu sehen
-- postgresql.conf:
log_lock_waits = on
deadlock_timeout = '1s'
log_line_prefix = '%m [%p] '

5. Die zugrunde liegende Sperr-Reihenfolge rekonstruieren

Der entscheidende Analyseschritt ist, aus den beiden Query-Texten im Log die Reihenfolge zu rekonstruieren, in der jede Transaktion ihre Ressourcen sperrt. Meist zeigt sich dabei ein Muster: Ein Codepfad sperrt Tabelle A vor Tabelle B, ein anderer, scheinbar unabhaengiger Codepfad sperrt dieselben Tabellen in umgekehrter Reihenfolge. Solange beide Pfade isoliert getestet werden, funktionieren sie einwandfrei, erst unter gleichzeitiger Ausfuehrung entsteht der Deadlock.

In der Praxis findet man diese Ursache oft in zwei getrennten Funktionen oder Services, die unabhaengig voneinander entwickelt wurden und beide dieselben zwei Tabellen anfassen, aber niemand hat je die Sperr-Reihenfolge zwischen ihnen abgestimmt. Wer Deadlocks aus Logs analysiert und dabei konsequent die Query-Reihenfolge beider Transaktions-Blocke vergleicht, findet diese Inkonsistenz meist innerhalb weniger Minuten, auch ohne den urspruenglichen Code-Autor zu befragen.

6. Warum die Datenbank genau diese Transaktion abbricht

Die Wahl des Opfers bei einem Deadlock, im Log als WE ROLL BACK TRANSACTION oder ueber die Prozess-ID im PostgreSQL-Log erkennbar, folgt keiner willkuerlichen Regel, sondern einer internen Heuristik. InnoDB waehlt typischerweise die Transaktion mit dem kleineren geschaetzten Rollback-Aufwand, gemessen an der Anzahl veraenderter Zeilen, als Opfer aus. PostgreSQL waehlt tendenziell die juengere der beiden Transaktionen.

Diese Information ist fuer die Analyse relevant, weil sie erklaert, warum bei wiederholten Deadlocks mit denselben zwei Codepfaden manchmal Transaktion A und manchmal Transaktion B abgebrochen wird, obwohl die Sperr-Reihenfolge dieselbe ist. Wer nur auf die Fehlermeldung im Anwendungscode schaut, koennte faelschlich annehmen, es handle sich um zwei verschiedene Probleme, obwohl die zugrunde liegende Ursache identisch ist.

7. Deadlocks dauerhaft erfassen statt einmalig lesen

Ein einzelner Log-Eintrag zeigt einen einzelnen Vorfall, aber nicht die Haeufigkeit oder den Trend ueber Zeit. Fuer die systematische Analyse empfiehlt sich, alle Deadlock-Eintraege aus dem Error-Log oder Server-Log automatisiert in eine strukturierte Tabelle zu extrahieren, etwa mit einem regelmaessig laufenden Parser-Skript. So laesst sich beantworten, ob die Deadlock-Rate nach einem Deployment gestiegen ist, welche zwei Tabellen am haeufigsten involviert sind, und ob bestimmte Tageszeiten besonders betroffen sind.

MySQL bietet zusaetzlich performance_schema.events_statements_history und explizite Deadlock-Zaehler in SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks', mit denen sich ein einfaches Monitoring-Dashboard ohne externe Werkzeuge aufbauen laesst. Wer Deadlocks aus Logs analysiert und diesen Zaehler in ein Standard-Monitoring-System wie Prometheus exportiert, erkennt einen ansteigenden Trend, bevor er zum akuten Produktionsproblem wird.


-- MySQL: kumulierten Deadlock-Zaehler seit Serverstart abrufen
SHOW GLOBAL STATUS LIKE 'Innodb_deadlocks';

-- PostgreSQL: Deadlock-Zaehler pro Datenbank
SELECT datname, deadlocks
FROM pg_stat_database
WHERE datname = current_database();

8. Von der Log-Analyse zur konkreten Code-Aenderung

Sobald die Sperr-Reihenfolge aus dem Log rekonstruiert ist, gibt es drei bewaehrte Korrekturen. Erstens: Beide Codepfade auf eine einheitliche, konsistente Sperr-Reihenfolge bringen, etwa immer zuerst nach Primaerschluessel aufsteigend sortiert sperren. Zweitens: Betroffene Updates in eine einzige Query zusammenfassen, wenn moeglich, um die Anzahl separater Sperroperationen zu reduzieren. Drittens: Explizite Sperren mit SELECT ... FOR UPDATE am Transaktionsanfang anfordern, statt implizit ueber spaetere UPDATE-Statements, um die Reihenfolge im Code sichtbar und kontrollierbar zu machen.

Ein haeufig uebersehener, aber wirksamer vierter Ansatz: Retry-Logik mit exponentiellem Backoff als Sicherheitsnetz ergaenzen, nachdem die eigentliche Ursache behoben ist. Deadlocks lassen sich in komplexen Systemen selten zu hundert Prozent ausschliessen, aber nach einer sauberen Analyse aus den Logs sinkt ihre Haeufigkeit typischerweise um Groessenordnungen, sodass Retry-Logik nur noch seltene Restfaelle abfaengt statt als Hauptstrategie zu dienen.

9. InnoDB- und PostgreSQL-Deadlock-Logs im Vergleich

Beide Systeme liefern die notwendigen Informationen, um Deadlocks aus Logs zu analysieren, unterscheiden sich aber in Format und Zugaenglichkeit deutlich.

Merkmal MySQL / InnoDB PostgreSQL
Standard-Verfuegbarkeit nur letzter Deadlock ohne Zusatzkonfiguration jeder Deadlock automatisch im Log
Aktivierung fuer Historie innodb_print_all_deadlocks = ON keine noetig, log_lock_waits optional
Query-Text im Log ja, vollstaendig pro Transaktion ja, im CONTEXT/STATEMENT-Abschnitt
Opfer-Heuristik geringster geschaetzter Rollback-Aufwand tendenziell juengere Transaktion
Zaehler fuer Monitoring Innodb_deadlocks (SHOW GLOBAL STATUS) pg_stat_database.deadlocks

Unabhaengig vom System gilt: Die Log-Struktur ist stabil genug, um eine automatisierte Auswertung zu bauen, statt jeden Deadlock manuell zu lesen. Wer diese Automatisierung einmal aufsetzt, kann Deadlocks aus Logs kontinuierlich analysieren, statt nur reaktiv nach Beschwerden zu reagieren.

Mironsoft

Deadlock-Analyse und Datenbank-Debugging fuer Produktivsysteme

Wiederkehrende Deadlocks statt Zufallsvorfaellen?

Wir lesen eure Deadlock-Logs, rekonstruieren die zugrunde liegende Sperr-Reihenfolge und liefern eine konkrete Code-Korrektur statt reiner Retry-Logik als Dauerloesung.

Log-Analyse

Bestehende Deadlock-Logs auswerten und Muster identifizieren

Ursachen-Fix

Sperr-Reihenfolge im Code vereinheitlichen statt nur Retry hinzuzufuegen

Monitoring-Setup

Deadlock-Zaehler ins bestehende Monitoring integrieren

10. Zusammenfassung

Deadlocks aus Logs zu analysieren verwandelt einen scheinbar zufaelligen Vorfall in eine praezise rekonstruierbare Sperr-Reihenfolge im Anwendungscode. Der InnoDB-Deadlock-Output ueber SHOW ENGINE INNODB STATUS und innodb_print_all_deadlocks, sowie das automatische PostgreSQL-Deadlock-Log, liefern beide alle notwendigen Informationen: die beteiligten Queries, die gehaltenen und angeforderten Sperren, und welche Transaktion abgebrochen wurde. Der Schluessel liegt darin, beide Transaktions-Blocke systematisch gegenueberzustellen, statt nur die Fehlermeldung im Anwendungscode zu lesen.

Nachhaltig geloest wird ein Deadlock-Problem erst, wenn die zugrunde liegende Sperr-Reihenfolge im Code vereinheitlicht wird, nicht durch Retry-Logik allein. Wer zusaetzlich Deadlock-Zaehler dauerhaft ins Monitoring integriert, erkennt einen ansteigenden Trend fruehzeitig und kann reagieren, bevor Deadlocks zum haeufigen Produktionsproblem werden.

Deadlocks aus Logs analysieren — Das Wichtigste auf einen Blick

InnoDB-Aktivierung

innodb_print_all_deadlocks = ON schreibt jeden Deadlock dauerhaft ins Error-Log, statt nur den letzten vorzuhalten.

Log-Struktur lesen

Zwei Transaktions-Blocke gegenueberstellen: wer haelt welche Sperre, wer wartet auf welche Sperre.

Ursache

Fast immer eine inkonsistente Sperr-Reihenfolge zwischen zwei unabhaengig entwickelten Codepfaden.

Fix

Einheitliche Sperr-Reihenfolge im Code, Retry-Logik nur als Sicherheitsnetz nach der eigentlichen Korrektur.

11. FAQ: Deadlocks aus Logs analysieren

1Vollstaendiges Deadlock-Logging in MySQL aktivieren?
SET GLOBAL innodb_print_all_deadlocks = ON. Ohne das haelt MySQL nur den letzten Deadlock vor.
2Besondere Einstellung fuer PostgreSQL noetig?
Nein, wird automatisch geloggt. log_lock_waits ergaenzt um Vorlaufzeit-Informationen.
3Abgebrochene Transaktion im InnoDB-Log erkennen?
Die Zeile WE ROLL BACK TRANSACTION nennt explizit die abgebrochene Transaktion.
4Warum variiert das Opfer manchmal?
InnoDB waehlt geringeren Rollback-Aufwand, PostgreSQL die juengere Transaktion. Bei gleicher Reihenfolge kann es trotzdem variieren.
5Reicht Retry-Logik als Loesung?
Nur als Sicherheitsnetz. Ohne Ursachenkorrektur steigt die Deadlock-Rate mit wachsender Last weiter.
6Sperr-Reihenfolge im Log finden?
Beide Transaktions-Blocke gegenueberstellen, das Kreuzmuster gehalten/wartend zeigt die inkonsistente Reihenfolge.
7Deadlock-Rate dauerhaft ueberwachen?
Innodb_deadlocks (MySQL) oder pg_stat_database.deadlocks (PostgreSQL), beide exportierbar nach Prometheus.
8Deadlock mit nur einer Tabelle moeglich?
Ja, bei unterschiedlicher Zeilen-Reihenfolge zwischen zwei Transaktionen auf derselben Tabelle.
9Schnellster Fix bei inkonsistenter Reihenfolge?
Alle Codepfade auf eine einheitliche Reihenfolge bringen, etwa immer aufsteigend nach Primaerschluessel sperren.
10Warum erst unter Last, nicht schon vorher?
Die inkonsistente Reihenfolge existiert unabhaengig von der Last, erst haeufige gleichzeitige Ausfuehrung erhoeht die Ueberschneidungswahrscheinlichkeit.