In PostgreSQL die Zeilen gesperrt werden, wie sie aktualisiert werden - in der Tat, die Art und Weise dies tatsächlich funktioniert, ist, dass jedes Tupel (Version einer Zeile) ein Systemfeld xmin
hat aufgerufen, um anzuzeigen, welche Transaktion, dass Tupel Strom gemacht (durch Einfügen oder Aktualisieren) und ein Systemfeld namens xmax
, um anzuzeigen, welche Transaktion das Tupel abgelaufen ist (durch Aktualisieren oder Löschen). Wenn Sie auf Daten zugreifen, überprüft es jedes Tupel, um festzustellen, ob es für Ihre Transaktion sichtbar ist, indem Sie Ihren aktiven "Snapshot" mit diesen Werten vergleichen.
Wenn Sie ein UPDATE ausführen und ein Tupel, das Ihren Suchbedingungen entspricht, ein xmin aufweist, das es für Ihren Snapshot und ein xmax einer aktiven Transaktion sichtbar macht, blockiert es und wartet darauf, dass diese Transaktion abgeschlossen wird. Wenn die Transaktion, die das Tupel zuerst aktualisiert hat, zurückrollt, wacht Ihre Transaktion auf und verarbeitet die Zeile. Wenn die erste Transaktion festgeschrieben wird, wird Ihre Transaktion abhängig von der aktuellen Isolationsstufe der Transaktion aktiviert.
Offensichtlich ist ein Deadlock das Ergebnis davon, dass Zeilen in anderer Reihenfolge auftreten. Es gibt keine Sperre auf Zeilenebene im RAM, die für alle Zeilen gleichzeitig verfügbar ist. Wenn jedoch Zeilen in der gleichen Reihenfolge aktualisiert werden, kann die Sperrung nicht aufgehoben werden. Leider garantiert die vorgeschlagene IN(1, 2)
Syntax das nicht. Verschiedene Sitzungen können verschiedene Kostenfaktoren aktiv haben, eine Hintergrund- "Analyse" -Aufgabe kann die Statistik für die Tabelle zwischen der Erzeugung eines Plans und der anderen ändern, oder sie kann einen Seqscan verwenden und von der PostgreSQL-Optimierung beeinflusst werden, die einen neuen Seqscan verursacht einem bereits laufenden Prozess beizutreten und "umherzulaufen", um Festplatten-E/A zu reduzieren.
Wenn Sie die Aktualisierungen nacheinander in der gleichen Reihenfolge, im Anwendungscode oder mit einem Cursor ausführen, haben Sie nur einfache Blockierungen, keine Deadlocks. Im Allgemeinen sind relationale Datenbanken jedoch anfällig für Serialisierungsfehler, und es empfiehlt sich, auf sie über ein Framework zuzugreifen, das sie basierend auf SQLSTATE erkennt und automatisch die gesamte Transaktion von Anfang an erneut versucht. In PostgreSQL wird ein Serialisierungsfehler immer einen SQLSTATE von 40001 oder 40P01 haben.
http://www.postgresql.org/docs/current/interactive/mvcc-intro.html
Vielen Dank! Also mein Beispiel oben kann einen Deadlock verursachen (weil wir die Reihenfolge nicht kennen, in der die Zeilen in beiden Transaktionen verarbeitet werden)? – vyakhir
Es könnte einen Deadlock verursachen, obwohl das selten wäre; im Gegensatz zum ersten Beispiel (explizite Auswahl unterschiedlicher Ordnungen), wo es üblich wäre. Sie können Deadlocks ausschließen, indem Sie für die Dauer jeder Transaktion, die die Tabelle aktualisiert, eine Sperre auf Tabellenebene mit der entsprechenden Stärke vornehmen, aber diese Heilung ist möglicherweise schlimmer als die Krankheit. Weitere Informationen finden Sie in dem Abschnitt, auf den ich verwiesen habe. – kgrittn
Aber veröffentlicht PostgreSQL die Sperre, nachdem die Zeile aktualisiert wurde, aber die gesamte UPDATE-Anweisung noch nicht beendet ist? Mit anderen Worten, wenn wir eine Aussage wie haben UPDATE ... WHERE ID IN (1,2,3,4,5) nach Postgresql Updates sagen, Zeile mit ID = 1 und fährt mit Zeile mit ID = 2, wird es die Zeile id = 1 freigeben? Wenn ja, wie wird es die Zeilen ggf. zurückrollen? – vyakhir