Deadlocks in Transaktionsdatenbanken sind ein klassisches Problem. Gefährlich werden sie aber erst dann, wenn sie so häufig auftreten, dass bestimmte Transaktionen nicht mehr möglich sind. Normalerweise müssen Sie Ihre Anwendungen so erstellen, dass sie immer bereit sind, eine Transaktion neu zu starten, wenn sie wegen eines Deadlocks zurückgerollt wurde.
InnoDB
benutzt automatische Zeilensperren.
Deadlocks können sogar bei Transaktionen auftreten, die nur
eine einzige Zeile einfügen oder löschen. Da diese Operationen
nicht wirklich „atomar“ sind, errichten sie
automatisch Sperren auf den (vielleicht mehreren)
Indexeinträgen der eingefügten oder gelöschten Zeile.
Folgende Techniken helfen Ihnen, mit Deadlocks fertigzuwerden und ihre Zahl zu reduzieren:
SHOW ENGINE INNODB STATUS
verrät Ihnen
den Grund des letzten Deadlocks. Dies kann Ihnen helfen,
Ihre Anwendung so zu tunen, dass Deadlocks vermieden werden.
Seien Sie immer bereit, eine Transaktion, die wegen eines Deadlocks scheiterte, neu zu starten. Deadlocks sind nichts Schlimmes. Versuchen Sie es einfach noch einmal.
Committen Sie Ihre Transaktionen oft. Kleine Transaktionen sind nicht so konfliktanfällig.
Wenn Sie Lesesperren (SELECT … FOR
UPDATE
oder … LOCK IN SHARE
MODE
) setzen, versuchen Sie, eine niedrigere
Isolationsebene einzustellen, beispielsweise READ
COMMITTED
.
Greifen Sie in einer festgelegten Reihenfolge auf Ihre Tabellen und Zeilen zu. Dann bilden die Transaktionen ordentliche Schlangen und können sich nicht gegenseitig blockieren.
Versehen Sie Ihre Tabellen mit guten Indizes. Dann müssen
Ihre Anfragen weniger Indexeinträge scannen und folglich
auch weniger Sperren setzen. Mit EXPLAIN
SELECT
können Sie feststellen, welche Indizes
nach Ansicht Ihres MySQL-Servers für Ihre Anfragen die
besten sind.
Sperren Sie nicht so viel. Wenn Sie es sich leisten können,
dass ein SELECT
Daten aus einem älteren
Snapshot zurückgibt, verzichten Sie auf die Klausel
FOR UPDATE
oder LOCK IN SHARE
MODE
. Die Isolationsebene READ
COMMITTED
ist gut geeignet, da jede konsistente
Leseoperation innerhalb derselben Transaktion Daten aus
einem eigenen, frischen Snapshot liest.
Wenn sonst nichts hilft, serialisieren Sie Ihre
Transaktionen mit Tabellensperren. Um LOCK
TABLES
mit Transaktionstabellen wie etwa
InnoDB
-Tabellen zu verwenden, setzen Sie
AUTOCOMMIT = 0
und rufen UNLOCK
TABLES
erst auf, nachdem Sie die Transaktion
explizit committet haben. Wenn Sie beispielsweise in die
Tabelle t1
schreiben und aus der Tabelle
t2
lesen möchten, tun Sie dies wie
folgt:
SET AUTOCOMMIT=0;
LOCK TABLES t1 WRITE, t2 READ, ...;
... do something with tables t1 and t2 here ...
COMMIT;
UNLOCK TABLES;
Tabellensperren sorgen dafür, dass Ihre Transaktions brav Schlange stehen und Deadlocks vermieden werden.
Sie können Transaktionen auch serialisieren, indem Sie eine
„Semaphoren“-Hilfstabelle mit nur einer
einzigen Zeile anlegen. Sorgen Sie dafür, dass jede
Transaktion diese Zeile aktualsieren muss, ehe sie auf
andere Tabellen zugreifen darf. Auf diese Weise laufen alle
Transaktionen nacheinander ab. Beachten Sie, dass der
Deadlock-Erkennungsalgorithmus von InnoDB
auch in diesem Falle funktioniert, da die serialisierende
Sperre auf Zeilenebene arbeitet. Bei MySQL-Tabellensperren
muss die Timeout-Methode eingesetzt werden, um Deadlocks
aufzulösen.
In Anwendungen, die den LOCK
TABLES
-Befehl verwenden errichtet MySQL keine
InnoDB
-Tabellensperren, wenn
AUTOCOMMIT=1
.
Dies ist eine Übersetzung des MySQL-Referenzhandbuchs, das sich auf dev.mysql.com befindet. Das ursprüngliche Referenzhandbuch ist auf Englisch, und diese Übersetzung ist nicht notwendigerweise so aktuell wie die englische Ausgabe. Das vorliegende deutschsprachige Handbuch behandelt MySQL bis zur Version 5.1.