Funktioniert ein COMMIT in einer anonymen plgpsql-Funktion in PostgreSQL 9.5?

8

Ich importiere eine große Anzahl großer Dateien in eine Reihe von Tabellen, die mithilfe von Schleifen in einem anonymen plpgsql-Codeblock partitioniert werden sollen $do$.

$do$
BEGIN
    FOR yyyy in 2012..2016 THEN 
        EXECUTE $$COPY table$$||yyyy||$$ FROM 'E:\data\file$$||yyyy||$$.csv DELIMITER ',' CSV;$$;
    END LOOP;
END;
$do$ LANGUAGE plpgsql

Dieser gesamte Vorgang sollte ungefähr 15 Stunden dauern, und ich hoffe, dass nicht alle Importe zurückgesetzt werden, wenn irgendwann ein Importfehler auftritt.

IIRC COMMITfunktioniert nicht in gespeicherten Funktionen, da die gesamte Funktion als einzelne Transaktion behandelt wird.

Aus der Dokumentation für$do$

Der Codeblock wird so behandelt, als wäre er der Hauptteil einer Funktion ohne Parameter, wodurch void zurückgegeben wird. Es wird einmal analysiert und ausgeführt.

Ich gehe davon aus, dass dies bedeutet, dass die gesamte $do$Transaktion eine Transaktion ist und Commits innerhalb des Blocks daher nicht funktionieren. Hab ich recht?

Raphael
quelle
1
Versuchen Sie BEGINoder COMMITim Funktionskörper. Sie erhalten eine Ausnahme, da dies nicht zulässig (nicht möglich) ist.
Erwin Brandstetter

Antworten:

9

Nein,

Sie können eine Transaktion innerhalb einer plpgsqlFunktion (oder eines anonymen Blocks) nicht steuern .

Die einzige Option, mit der Sie eine Transaktion außerhalb des Blocks erstellen können, z.

BEGIN;

DO $$
  -- function stuff

  -- but if you use a exception, you will force a rollback
  RAISE EXCEPTION 'message';
$$ LANGUAGE 'plpgsql';

COMMIT; -- OR ROLLBACK

Übrigens, DO BLOCKShaben den gleichen Effekt wie Funktionen, die zurückkehren void.

Weitere Informationen finden Sie im Dokument:

Sebastian Webber
quelle
Wissen wir, ob dies noch der Fall ist? Ich habe eine Funktion, die mehrere hundert Mal wiederholt werden muss. Die erste Runde dauert 2 Sekunden, nachdem die 7. fast eine Stunde ist, und ich habe nach der 10. Runde nichts mehr gesehen.
Dennis Bauszus
1

Die einzige Lösung, die innerhalb von "DO" -Blöcken (oder Funktionen) (für Postgresql-Version unter 11) festgeschrieben werden kann, besteht darin, eine dblink-Verbindung zu demselben Server zu verwenden und Ihre Abfragen dort auszuführen. Denken Sie nur an die Sichtbarkeit von Variablen und temporären Objekten.

Weitere Informationen zu dblink Ab Postgresql-11 ist die Transaktionssteuerung innerhalb des "DO" -Blocks verfügbar, während "DO-Block" nicht in einer anderen Transaktion ausgeführt wird.

Dzhureedzh
quelle
postgresql.org/docs/11/sql-do.html gibt an, dass Transaktionssteuerungsanweisungen nur zulässig sind, wenn DO in einer eigenen Transaktion ausgeführt wird. Dies stimmte natürlich nicht mit 9.5. OTOH mit dblinkIhnen öffnet eine weitere Transaktion, sodass Ihr COMMITAnruf dort keine Auswirkungen auf die anrufende Transaktion hat, wenn ich mich nicht irre.
Dekso
Mein Fehler. Die Transaktionskontrolle innerhalb von "DO" wurde in Postgresql-11 eingeführt. Ich überprüfe nur, ob 10.4 immer noch nicht funktioniert.
Dzhureedzh
@dezso Vielen Dank, dass Sie mich darauf hingewiesen haben. Ich habe die dblink-Methode sogar auf PG11-Servern verwendet.
Dzhureedzh