Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Soll SELECT ... FOR UPDATE immer ORDER BY enthalten?

Ihr Beispiel in Ihrer Frage zeigt, dass die Sperrreihenfolge von der Zugriffsmethode abhängt. Dieser Zugriffspfad wird nicht direkt durch die ORDER BY-Klausel der Abfrage bestimmt, es gibt viele Faktoren, die diesen Zugriffspfad beeinflussen können. Daher können Sie einen Deadlock nicht einfach durch Hinzufügen eines ORDER BY verhindern, da Sie immer noch zwei unterschiedliche Zugriffspfade haben könnten. Tatsächlich konnte ich durch Ausführen Ihres Testfalls mit der Reihenfolge by und Ändern der Sitzungsparameter bewirken, dass zwei Sitzungen mit derselben Abfrage auf einen ORA-60 laufen.

Wenn für die beteiligten Sitzungen keine andere Sperre ansteht, werden die Zeilen in derselben Reihenfolge gesperrt in allen Sitzungen verhindert Deadlocks, aber wie können Sie diese Reihenfolge zuverlässig erzwingen? Beachten Sie, dass dies sowieso nur diesen sehr speziellen Fall von Deadlock verhindern würde. Sie könnten immer noch Deadlocks mit mehreren Abfragen in jeder Sitzung oder unterschiedlichen Plänen bekommen.

In der Praxis ist dieser Fall wirklich etwas Besonderes und sollte sowieso nicht oft vorkommen:Wenn Sie sich Sorgen um Deadlocks machen, denke ich, dass es immer noch einfachere Methoden gibt, sie zu verhindern.

Der einfachste Weg, einen Deadlock zu verhindern, ist die Verwendung von FOR UPDATE NOWAIT oder FOR UPDATE WAIT X (obwohl WAIT X immer noch einen Deadlock mit Werten von X auslösen kann, die dem Deadlock-Erkennungsmechanismus überlegen sind, derzeit 3 ​​Sekunden ab 11g, glaube ich -- danke @APC für die Korrektur).

Mit anderen Worten, beide Transaktionen sollten fragen:Geben Sie mir diese Zeilen und sperren Sie sie, aber wenn ein anderer Benutzer bereits eine Sperre hat, geben Sie einen Fehler zurück, anstatt auf unbestimmte Zeit zu warten. Es ist das unbestimmte Warten, das Deadlocks verursacht.

In der Praxis würde ich sagen, dass die meisten Anwendungen mit realen Benutzern lieber sofort einen Fehler erhalten, als dass eine Transaktion auf unbestimmte Zeit auf den Abschluss einer anderen Transaktion wartet. Ich würde FOR UPDATE in Betracht ziehen ohne NOWAIT nur für unkritische Batch-Jobs.