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

Sperre und Transaktion in Postgres, die eine Abfrage blockieren sollte

Das von Ihnen beschriebene Verhalten ist normal und wird in jeder transaktionalen relationalen Datenbank erwartet.

Wenn PostgreSQL Ihnen den Wert edited anzeigt für das erste SELECT es wäre falsch, dies zu tun - das nennt man "Dirty Read" und ist eine schlechte Nachricht in Datenbanken.

PostgreSQL würde beim SELECT warten dürfen bis Sie einen Commit oder Rollback durchgeführt haben, der SQL-Standard dies jedoch nicht erfordert, Sie ihm nicht mitgeteilt haben, dass Sie warten möchten, und es aus technischen Gründen nicht warten muss, sodass die angeforderten Daten zurückgegeben werden für sofort. Immerhin, bis es festgeschrieben ist, update existiert nur irgendwie - es könnte immer noch passieren oder auch nicht.

Wenn PostgreSQL hier immer warten würde, würden Sie schnell in eine Situation geraten, in der nur eine Verbindung gleichzeitig etwas mit der Datenbank tun könnte. Nicht schön für die Leistung und die meiste Zeit völlig unnötig.

Wenn Sie auf ein gleichzeitiges UPDATE warten möchten (oder DELETE ), würden Sie SELECT ... FOR SHARE verwenden . (Beachten Sie jedoch, dass dies für INSERT nicht funktioniert ).

Einzelheiten:

SELECT ohne FOR UPDATE oder FOR SHARE -Klausel nimmt keine Sperren auf Zeilenebene. Es sieht also, was auch immer die aktuell festgeschriebene Zeile ist, und wird nicht von In-Flight-Transaktionen beeinflusst, die diese Zeile möglicherweise ändern. Die Konzepte werden im MVCC-Abschnitt der Dokumentation erklärt . Die allgemeine Idee ist, dass PostgreSQL Copy-on-Write ist, mit einer Versionierung, die es ermöglicht, die richtige Kopie zurückzugeben, basierend darauf, was die Transaktion oder Anweisung zum Zeitpunkt ihres Starts "sehen" konnte - was PostgreSQL einen "Snapshot" nennt.

In der Voreinstellung READ COMMITTED Isolations-Snapshots werden auf Anweisungsebene erstellt, wenn Sie also SELECT eine Reihe, COMMIT eine Änderung von einer anderen Transaktion und SELECT Auch hier sehen Sie unterschiedliche Werte sogar innerhalb einer Transaktion. Sie können SNAPSHOT verwenden isolation, wenn Sie nicht möchten, dass Änderungen festgeschrieben werden, nachdem die Transaktion begonnen hat, oder SERIALIZABLE Isolierung, um weiteren Schutz gegen bestimmte Arten von Transaktionsabhängigkeiten hinzuzufügen.

Siehe das Kapitel zur Transaktionsisolierung in der Dokumentation .

Wenn Sie ein SELECT möchten Um auf laufende Transaktionen zu warten, um Änderungen an ausgewählten Zeilen festzuschreiben oder rückgängig zu machen, müssen Sie SELECT ... FOR SHARE verwenden . Dadurch wird die von einem UPDATE übernommene Sperre blockiert oder DELETE bis die Transaktion, die die Sperre übernommen hat, rückgängig gemacht oder festgeschrieben wird.

INSERT ist jedoch anders - die Tupel existieren einfach nicht für andere Transaktionen, bis sie festgeschrieben werden. Die einzige Möglichkeit, auf gleichzeitiges INSERT zu warten s ist ein EXCLUSIVE zu nehmen Sperre auf Tabellenebene, damit Sie wissen, dass niemand sonst die Tabelle ändert, während Sie sie lesen. Normalerweise bedeutet dies jedoch, dass Sie ein Designproblem in der Anwendung haben - Ihre App sollte sich nicht darum kümmern wenn es nicht festgeschriebene insert gibt ist noch im Flug.

Siehe das Kapitel zum expliziten Sperren der Dokumentation .