4

私は自分のアプリケーションの一部をプロファイリングしてきましたが、まったく同じスクリプトを実行する際に、PgAdmin3 が psql よりも大幅に高速であることがわかりました。Unix ソケット、Ubuntu 12.04、Postgresql 9.1、および pgadmin3 v1.14 を使用しています。次のような簡単なスクリプトがあります。

BEGIN
INSERT INTO key_value(section,key,value) VALUES('section','key1','value');
....
INSERT INTO key_value(section,key,value) VALUES('section','key10000','value');
COMMIT;

ここにテーブルがあります:

CREATE TABLE key_value
(
  key text NOT NULL,
  value text,
  CONSTRAINT key_value_pkey PRIMARY KEY (section , key )
)
WITH (
  OIDS=FALSE
);

このスクリプトには 10000 の挿入があります。pgadmin3 で実行すると約 0.5 秒、psql で実行すると 2.5 ~ 3.5 秒かかります。どちらもトランザクションにラップされているため、実際には違いはありません。テーブルを再作成したり、完全なバキュームを実行したりしても、結果は一貫しています。Postgresql サーバーにログを記録すると、psql で実行された場合はすべての挿入ステートメントに対して postgres がログを記録していることが示されますが、pgadmin3 から実行された場合は 1 つのログしか記録されません。

psql の実行は次のように行われます。

psql  -n -t -f p.sql -o/dev/null

また、テスト済み

psql  -n -t -1 -f p.sql -o/dev/null

私の質問は、なぜ psql が非常に遅いのか、postgresql が一方のクライアントではすべてのステートメントをログに記録するのに、もう一方のクライアントではトランザクション全体のみをログに記録する理由と、psql に簡単な修正があるかどうかです。

編集明確にするために、ステートメントではなく期間を記録しています:

サーバーでは、psqlで実行すると次のようになります

2012-10-02 12:20:32 CEST LOG:  duration: 0.283 ms
....
2012-10-02 12:20:35 CEST LOG:  duration: 0.285 ms
2012-10-02 12:20:35 CEST LOG:  duration: 0.291 ms
2012-10-02 12:20:35 CEST LOG:  duration: 0.279 ms
2012-10-02 12:20:35 CEST LOG:  duration: 0.284 ms
2012-10-02 12:20:35 CEST LOG:  duration: 0.279 ms
2012-10-02 12:20:35 CEST LOG:  duration: 0.299 ms
....
2012-10-02 12:20:36 CEST LOG:  duration: 5.779 ms

pgadmin3 で実行する場合:

2012-10-02 12:23:21 CEST LOG:  duration: 532.695 ms

ユーザーとデータベースは psql と pgadmin3 で同じです

4

2 に答える 2

3

ヒント:pgAdminはスクリプトを1つのマルチステートメントとして実行するため、ネットワーク(プロトコル)のオーバーヘッドが少なくなります。

于 2012-10-02T11:29:08.730 に答える
1

psqlには、セミコロンをステートメントの区切り記号として認識する統合パーサーがあります。Pavel's answerで述べたように、pgadmin とは対照的に、SQL スクリプトを複数のステートメントに分割するために使用します。

この動作をオフにするオプションはありません。ただし、DO 匿名コード ブロックを使用すると、ほとんど変更せずに同様の結果が得られるはずです。スクリプトを次のように記述した場合:

DO $$
BEGIN
INSERT INTO key_value(section,key,value) VALUES('section','key1','value');
....
INSERT INTO key_value(section,key,value) VALUES('section','key10000','value');
END $$;

これは pgadmin と同じように一度にサーバーに送信され (技術的にはかなり異なりますが)、おそらく同等の時間で実行されます。

編集: @vseguip コメントによると、これらの 10k ステートメントで plpgsql インタープリターが費やす時間が原因で、これは効率的ではありません。

別のアイデア: スクリプトを変更して、複数の INSERT ではなく、複数の行を持つ 1 つの INSERT のみを持ち、DO ブロックを持たないようにします。

BEGIN;
INSERT INTO key_value(section,key,value) VALUES('section','key1','value'),
      ('section','key2','value'),
      ('section','key3','value'),
      ....
      ('section','key10000','value');
END;
于 2012-10-02T14:45:42.813 に答える