COMMITはPostgreSQL 9.5の匿名のplgpsql関数内で機能しますか?


8

匿名のplpgsqlコードブロック内のループを使用して、多数の大きなファイルをいくつかのテーブルにインポートしてパーティション分割します$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

このプロセス全体には約15時間かかります。ある時点でインポートエラーが発生した場合、すべてのインポートがロールバックされないことを願っています。

IIRC COMMITは、関数全体が単一のトランザクションとして扱われるため、ストアド関数内では機能しません。

ドキュメントから$do$

コードブロックは、パラメーターのない関数の本体であるかのように扱われ、voidを返します。解析と実行は1回です。

これは、全体$do$が1つのトランザクションであるため、ブロック内のコミットが機能しないことを想定しています。私は正しいですか?


1
BEGINまたはCOMMIT関数本体で試してください。許可されていない(不可能)ため、例外が発生します。
Erwin Brandstetter 2016

回答:


9

番号、

plpgsql関数(または無名ブロック)内のトランザクションを制御することはできません。

あなたがブロックの外でトランザクションを作成する唯一のオプション、例えば:

BEGIN;

DO $$
  -- function stuff

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

COMMIT; -- OR ROLLBACK

ところで、DO BLOCKS戻り値を返す関数と同じ効果がありますvoid

詳しくはドキュメントをご覧ください:


これがまだ当てはまるかどうか知っていますか?私は数百回ループする必要がある関数を持っています。最初のループは7番目のループが1時間近くになった後2秒かかり、10番目のループの後は何も見ていません。
Dennis Bauszus 2017年

1

「DO」ブロック(または関数)内でコミットする唯一の解決策(Postgresqlバージョンが11未満の場合)は、同じサーバーへのdblink接続を使用してそこでクエリを実行することです。変数と一時オブジェクトの可視性を覚えておいてください。

dblinkの詳細 Postgresql-11以降、「DO」ブロック内からのトランザクション制御は、「DOブロック」が他のトランザクション内で実行されていないときに使用できます。


postgresql.org/docs/11/sql-do.htmlには、「DOが独自のトランザクションで実行される場合にのみトランザクション制御ステートメントが許可される」と記載されています。もちろん、これは9.5では当てはまりませんでした。OTOHがdblinkあなたと別のトランザクションを開くので、COMMIT私が間違っていなければ、そこでの呼び出しは呼び出しトランザクションに影響を与えません。
dezso

私の悪い。「DO」内のトランザクション制御はPostgresql-11で導入されました。10.4でまだ動作しないことを確認しました。
Dzhureedzh

@dezso指摘していただきありがとうございます。PG11サーバーでもdblinkメソッドを使用していました。
Dzhureedzh
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.