[pgsql-jp: 38907] Re: 大量のデータの登録時に、メモリ不足エラー

ITAGAKI Takahiro itagaki.takahiro @ oss.ntt.co.jp
2007年 10月 29日 (月) 18:43:22 JST


板垣です。

"笹倉 雅和" <sasakura @ technicalunion.co.jp> wrote:

> 言語は、PowerBuilderというものですが、関数の内部動作などは、おそらく
> 察しがつくのではないかと思います。

PostgreSQL というより、PowerBuilder によるものではないでしょうか?
演算や関数で使ったメモリは、行単位 or SQL単位で ほぼ確実に解放されます。
複雑な関数を使用されているわけでもなさそうなので、なおさらです。

PowerBuilder は、SQL を毎回 PREPARE して実行するような作りになっていませんか?
SQL の発行ごとに、サーバに Prepared Statement オブジェクトをリークしていないか
疑っています。

PL/pgSQL で処理を似せて、実験してみました。
t_without_prep() のほうは、サーバの消費メモリはほとんど増えませんが、
t_with_prep() では、大量にメモリを消費します。(20万件で500MBほど)
これと似たような動作になっていないでしょうか?

他に可能性があるサーバオブジェクトは、カーソルがあります。
ループの中で、定期的に
  SELECT count(*) FROM pg_prepared_statements;
  SELECT count(*) FROM pg_cursors;
を実行してみると、リークの様子が観察できます。

もしこれらが原因ならば、PowerBuilder を使っている限り、
トランザクションを短く切るしかないかもしれません。


---- PL/pgSQL で似せた処理
CREATE TABLE t_base (i integer);
INSERT INTO t_base SELECT generate_series(1, 200000);

-- Prepared Statement を使用しない
CREATE TABLE t_without_prep (LIKE t_base);
CREATE OR REPLACE FUNCTION without_prep() RETURNS VOID AS $$
  DECLARE
    r record;
  BEGIN
    TRUNCATE t_without_prep;
    FOR r IN SELECT * FROM t_base LOOP
      INSERT INTO t_without_prep(i) VALUES(r.i);
    END LOOP;
  END;
$$ LANGUAGE plpgsql;
SELECT without_prep();

-- Prepared Statement を使用する(解放しない)
CREATE TABLE t_with_prep (LIKE t_base);
CREATE OR REPLACE FUNCTION with_prep() RETURNS VOID AS $$
  DECLARE
    r record;
  BEGIN
    TRUNCATE t_with_prep;
    FOR r IN SELECT * FROM t_base LOOP
      EXECUTE 'PREPARE p_' || r.i || '(integer) AS ' ||
              'INSERT INTO t_with_prep(i) VALUES($1)';
      EXECUTE 'EXECUTE p_' || r.i || '(' || r.i || ')';
    END LOOP;
  END;
$$ LANGUAGE plpgsql;
SELECT with_prep();




pgsql-jp メーリングリストの案内