In PostgreSQL werden die Zeilen gesperrt, wenn sie aktualisiert werden – tatsächlich funktioniert das so, dass jedes Tupel (Version einer Zeile) ein Systemfeld namens xmin
hat um anzuzeigen, welche Transaktion dieses Tupel aktuell gemacht hat (durch Einfügen oder Aktualisieren) und ein Systemfeld namens xmax
um anzuzeigen, welche Transaktion dieses 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 es Ihren aktiven "Schnappschuss" mit diesen Werten vergleicht.
Wenn Sie ein UPDATE ausführen und ein Tupel, das Ihren Suchbedingungen entspricht, ein xmin hat, das es für Ihren Snapshot sichtbar machen würde, und ein xmax einer aktiven Transaktion, blockiert es und wartet darauf, dass diese Transaktion abgeschlossen wird. Wenn die Transaktion, die das Tupel zuerst aktualisiert hat, zurückgesetzt wird, wacht Ihre Transaktion auf und verarbeitet die Zeile. Wenn die erste Transaktion festgeschrieben wird, wacht Ihre Transaktion auf und ergreift Maßnahmen, abhängig von der aktuellen Transaktionsisolationsstufe.
Offensichtlich ist ein Deadlock das Ergebnis davon, dass Zeilen in unterschiedlicher Reihenfolge auftreten. Es gibt keine Sperre auf Zeilenebene im RAM, die für alle Zeilen gleichzeitig erhalten werden kann, aber wenn Zeilen in derselben Reihenfolge aktualisiert werden, können Sie keine Zirkularsperre haben. Leider ist der vorgeschlagene IN(1, 2)
Syntax garantiert das nicht. In verschiedenen Sitzungen können unterschiedliche Kostenfaktoren aktiv sein, eine Hintergrund-„Analyse“-Aufgabe kann Statistiken für die Tabelle zwischen der Generierung eines Plans und des anderen ändern, oder sie verwendet möglicherweise einen Seqscan und ist von der PostgreSQL-Optimierung betroffen, die einen neuen Seqscan verursacht um sich einem bereits laufenden anzuschließen und "herumzuschleifen", um die Festplatten-E/A zu reduzieren.
Wenn Sie die Aktualisierungen einzeln in derselben Reihenfolge im Anwendungscode oder mit einem Cursor durchführen, haben Sie nur einfache Blockierungen, keine Deadlocks. Im Allgemeinen sind relationale Datenbanken jedoch anfällig für Serialisierungsfehler, und es ist am besten, auf sie über ein Framework zuzugreifen, das sie basierend auf SQLSTATE erkennt und automatisch die gesamte Transaktion von Anfang an wiederholt. In PostgreSQL hat ein Serialisierungsfehler immer einen SQLSTATE von 40001 oder 40P01.
http://www.postgresql.org/docs/current/interactive/mvcc-intro.html