PostgreSQL-Fehler: deadlock detected

ERROR:  deadlock detected
DETAIL:  Process 18461 waits for ShareLock on transaction 1064; blocked by process 18463.
Process 18463 waits for ShareLock on transaction 1063; blocked by process 18461.
HINT:  See server log for query details.
CONTEXT:  while updating tuple (0,3) in relation "accounts"

Zwei (oder mehr) Transaktionen warten jeweils auf einen Lock, den die andere hält. Keine kann jemals fortfahren, daher erkennt PostgreSQL den Zyklus, wählt eine Transaktion als Opfer aus und bricht sie mit diesem Fehler ab. Die andere Transaktion läuft normal weiter.

Was dieser Fehler bedeutet

Sperren auf Zeilenebene werden in PostgreSQL gehalten, bis die Transaktion committet oder zurückrollt. Wenn Transaktion A Zeile 1 sperrt und dann Zeile 2 will, während Transaktion B Zeile 2 hält und Zeile 1 will, bilden sie einen Zyklus: einen Deadlock. Wenn ein Backend länger als deadlock_timeout (Standard: 1 Sekunde) auf einen Lock gewartet hat, führt PostgreSQL eine Deadlock-Prüfung durch; findet es einen Zyklus, bricht es einen der Beteiligten mit SQLSTATE 40P01, dem Geschwister von 40001, ab.

Wichtige Einordnung: Die Datenbank hat die Situation bereits aufgelöst, wenn Sie den Fehler sehen. Nichts ist beschädigt, und die überlebende Transaktion hat ihre Lock-Wartezeit abgeschlossen. Was bleibt, ist ein Anwendungsproblem — die abgebrochene Transaktion wurde zurückgerollt und ihre Arbeit ist verloren, deshalb muss Ihre Anwendung darauf vorbereitet sein, sie zu wiederholen.

Häufige Ursachen

So diagnostizieren Sie ihn

Der Fehler selbst enthält das meiste, was Sie brauchen:

Setzen Sie log_lock_waits = on, um auch jede Lock-Wartezeit zu protokollieren, die länger als deadlock_timeout dauert; das zeigt Ihnen die Beinahe-Kollisionen, nicht nur die tatsächlichen. Für die Live-Untersuchung, wer wen blockiert:

SELECT waiting.pid  AS waiting_pid,  waiting.query  AS waiting_query,
       blocking.pid AS blocking_pid, blocking.query AS blocking_query
FROM pg_stat_activity waiting
JOIN pg_stat_activity blocking
  ON blocking.pid = ANY (pg_blocking_pids(waiting.pid));

So beheben Sie ihn

🔍 Weiterführend: Transaktions-Isolationsebenen — der Abschnitt "Korrektes Wiederholen" gilt auch für Deadlocks: die gesamte Transaktion wiederholen, nicht die fehlgeschlagene Anweisung.