[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 メーリングリストの案内