PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Fehler im PostgreSQL-Sperrmechanismus oder Missverständnis des Mechanismus

Es gibt keinen Fehler, und ich glaube nicht, dass Sie irgendetwas missverstehen; Ihnen fehlen nur ein paar Teile des Puzzles.

Fremdschlüssel werden intern unter Verwendung von Sperren auf Zeilenebene implementiert; Beginnend mit Postgres 8.1 und bis zu 9.2, wann immer Sie die Referenzierungstabelle aktualisieren (apples in diesem Fall) wird eine Abfrage ausgelöst, die SELECT FOR SHARE ausführt auf der referenzierten Tabelle (trees ). Also SELECT FOR UPDATE in der ersten Transaktion blockiert der SELECT FOR SHARE der referentiellen Integrität für die zweite Transaktion. Dies verursacht die Blockierung im zweiten Befehl.

Jetzt höre ich dich schreien:„Warte! Wie kommt es, dass es beim zweiten Befehl blockiert und nicht beim ersten? Die Erklärung ist wirklich einfach – das liegt nur daran, dass es eine einfache Optimierung gibt, die das interne SELECT FOR SHARE überspringt wenn der Schlüssel nicht geändert wird. Dies ist jedoch insofern vereinfachend, als diese Optimierung nicht ausgelöst wird, wenn Sie ein Tupel ein zweites Mal aktualisieren, da es schwieriger ist, die ursprünglichen Werte aufzuspüren. Daher die Blockade.

Sie fragen sich vielleicht auch, warum ich gesagt habe, dass dies bis zu 9.2 ist --- was ist mit 9.3? Der Hauptunterschied besteht darin, dass in 9.3 SELECT FOR KEY SHARE verwendet wird , das ist eine neue, leichtere Sperrstufe; es ermöglicht eine bessere Parallelität. Wenn Sie Ihr Beispiel in 9.3 ausprobieren und auch den SELECT FOR UPDATE ändern zu SELECT FOR NO KEY UPDATE (Das ist ein leichterer Modus als SELECT FOR UPDATE das besagt, dass Sie das Tupel vielleicht aktualisieren werden, aber Sie versprechen, den Primärschlüssel nicht zu ändern und ihn nicht zu löschen), sollten Sie sehen, dass er nicht blockiert. (Sie können auch ein UPDATE in der referenzierten Zeile versuchen, und wenn Sie den Primärschlüssel nicht ändern, wird er auch nicht blockiert.)

Dieses 9.3-Zeug wurde durch einen Patch von Ihnen als http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0ac5ad5134f2769ccbaefec73844f8504c4d6182 und ich denke, es war ein ziemlich cooler Hack (Die Commit-Nachricht enthält einige weitere Details, falls Sie sich für solche Dinge interessieren). Aber Vorsicht, verwenden Sie keine Versionen vor 9.3.4, da dieser Patch so enorm komplex war, dass einige schwerwiegende Fehler unbemerkt blieben und erst kürzlich behoben wurden.