MVCC
Zunächst einmal, wenn "normale Operationen" aus SELECT
bestehen Abfragen, das MVCC-Modell kümmert sich automatisch darum. UPDATE
blockiert SELECT
nicht und umgekehrt. SELECT
sieht nur festgeschriebene Daten (oder was in derselben Transaktion gemacht wurde), also das Ergebnis des großen UPDATE
bleibt für andere Transaktionen unsichtbar, bis es fertig ist (festgeschrieben).
Leistung / Aufblasen
Wenn Sie haben keine anderen Objekte, die auf diese Tabelle verweisen,
und Sie haben keine gleichzeitigen Schreibvorgänge (die verloren gehen würden!),
und Sie können sich eine sehr kurze exklusive Sperre für den Tisch leisten,
und Sie haben natürlich den zusätzlichen Speicherplatz:
Sie könnten die Sperrung auf ein Minimum reduzieren, indem Sie im Hintergrund eine aktualisierte Version der Tabelle erstellen. Stellen Sie sicher, dass es alles hat um ein Drop-in-Ersatz zu sein, dann lösche das Original und benenne das Dupe um.
CREATE TABLE tbl_new (LIKE tbl_org INCLUDING CONSTRAINTS);
INSERT INTO tbl_new
SELECT col_a, col_b, array[col] aS col_c
FROM tbl_org;
Ich verwende CREATE TABLE (LIKE .. INCLUDING CONSTRAINTS)
, weil (hier das Handbuch zitieren):
Nicht-Null-Einschränkungen werden immer in die neue Tabelle kopiert. CHECK
Einschränkungen werden nur kopiert, wenn INCLUDING CONSTRAINTS
angegeben ist; andere Arten von Beschränkungen werden niemals kopiert.
Stellen Sie sicher, dass der neue Tisch fertig ist. Dann:
DROP tbl_org;
ALTER TABLE tbl_new RENAME TO tbl_org;
Führt zu einem sehr kurzen Zeitfenster, in dem der Tisch exklusiv gesperrt wird.
Hier geht es wirklich nur um Leistung. Es erstellt ziemlich schnell eine neue Tabelle ohne Aufblasen. Wenn Sie Fremdschlüssel oder -ansichten haben, können Sie immer noch diesen Weg gehen, aber Sie müssen ein Skript vorbereiten, um diese Objekte zu löschen und neu zu erstellen, wodurch möglicherweise zusätzliche exklusive Sperren erstellt werden.
Gleichzeitige Schreibvorgänge
Bei gleichzeitigen Schreibvorgängen ist eigentlich alles, was Sie tun können, Ihr Update in Stücke aufzuteilen. Das ist nicht in einer einzigen Transaktion möglich, da Sperren erst am Ende einer Transaktion aufgehoben werden.
Sie könnten Verwenden Sie dblink , die unabhängige Transaktionen auf einer anderen Datenbank, einschließlich sich selbst, starten kann. Auf diese Weise könnten Sie alles in einem einzigen DO
erledigen -Anweisung oder eine plpgsql-Funktion mit einer Schleife. Hier ist eine lose verwandte Antwort mit weiteren Informationen zu dblink:
- Datenbank aus gespeicherter Prozedur in PostgreSQL löschen oder erstellen
Ihr Ansatz mit Cursorn
Ein Cursor innerhalb der Funktion wird Ihnen nichts kaufen . Jede Funktion wird automatisch in eine Transaktion eingeschlossen, und alle Sperren werden erst am Ende der Transaktion aufgehoben. Auch wenn Sie CLOSE cursor
verwendet haben (was Sie nicht tun) würde es nur einige Ressourcen freigeben, aber nicht Geben Sie erworbene Sperren für die Tabelle frei. Ich zitiere das Handbuch:
CLOSE
schließt das Portal unter einem geöffneten Cursor. Dies kann verwendet werden, um Ressourcen vor dem Ende der Transaktion freizugeben oder um die Cursorvariable freizugeben, damit sie erneut geöffnet werden kann.
Sie müssten separat ausgeführt werden Transaktionen oder (missbrauchen) Sie dblink, das das für Sie erledigt.