[pgsql-jp: 41475] Re: AutoCommitをfalseにするとレスポンスが遅くなる

pascalpascal @ snow.plala.or.jp pascalpascal @ snow.plala.or.jp
2013年 7月 25日 (木) 18:40:50 JST


笠原さん、MauMauさん

宮本です。

情報ありがとうございます。

> そのため、9.2にアップグレードすることが解決方法の1つだと考えます。

何となくですが、これのような気がしますね。
少し時間がかかりますが、テストしてみます。

> サーバ側にバインド変数を含むSQL文が送られているかどうか、つまり、
> SQL文中に$1などが含まれるかどうかを見ます。

ログを確認しましたが、
バインド変数は早い方も遅い方もSQL文の中に出力されていました。
(SQL文が長いので、ここでは省略していますが、実際のログには
出力されていました。)
気になるのは、遅い方(AutoCommit=false)は、"execute S_2/C_3"
のように、prepare文に名前がついていることです。

早い方(AutoCommit=true)は、execute <unnamed> になっています。

■遅い方

2013-07-24 16:18:22 JST 11503 LOG:  execute S_1: BEGIN
2013-07-24 16:18:22 JST 11503 LOG:  execute S_2/C_3: SELECT COUNT(*) FROM ( SELECT ・・・
2013-07-24 16:18:22 JST 11503 DETAIL:  parameters: $1 = '00060000', $2 = '00060000', $3 = '', $4 = '', $5 = '', $6 = '', $7 = '', $8 = '', $9 = '', $10 = '', $11 = '', $12 = '', $13 = '3', $14 = '3'

■早い方

2013-07-24 16:25:09 JST 14734 LOG:  execute <unnamed>: SELECT COUNT(*) FROM ( SELECT ・・・
2013-07-24 16:25:09 JST 14734 DETAIL:  parameters: $1 = '00060000', $2 = '00060000', $3 = '', $4 = '', $5 = '', $6 = '', $7 = '', $8 = '', $9 = '', $10 = '', $11 = '', $12 = '', $13 = '3', $14 = '3'
	
	
プログラムソースは以下の通りです。setPrepareThresholdはテストで入れたものです。

----------------------------------------------------------------------import java.io.File;
import java.sql.*;
import java.util.Properties;
import java.util.List;
import org.postgresql.PGStatement.*;


public class Test2online3ac {

	public static void main(String[] args) {
		try {
			Class.forName("org.postgresql.Driver");
			Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:xxxxx/xxxxx", "xxxxx", "xxxxx");

			conn.setAutoCommit(false);

			String sql = "SELECT COUNT(*) FROM ( SELECT ・・・省略

			PreparedStatement st = conn.prepareStatement(sql);
			st.setFetchSize(1000);
			st.setObject(1, "00060000");
			st.setObject(2, "00060000");
			st.setObject(3, "");
			st.setObject(4, "");
			st.setObject(5, "");
			st.setObject(6, "");
			st.setObject(7, "");
			st.setObject(8, "");
			st.setObject(9, "");
			st.setObject(10, "");
			st.setObject(11, "");
			st.setObject(12, "");
			st.setObject(13, "3");
			st.setObject(14, "3");

			System.out.println("AutoCommit is "+conn.getAutoCommit());

			org.postgresql.PGStatement pgstmt = (org.postgresql.PGStatement)st;
			pgstmt.setPrepareThreshold(0);

			long stime = System.currentTimeMillis();
			st.executeQuery();
			conn.commit();
			long etime = System.currentTimeMillis();
			System.out.println("経過時間:" + (etime - stime));

			st.close();

			conn.close();

		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

}


以上

---- MauMau <maumau307 @ gmail.com> さんは書きました: 
> MauMauです。
> 
> > 遅い方の実行計画はプラン中に$1や$2などが見えますので、値がバインドされる前の 
> > 
> > 汎用的な実行計画に見えます。
> > 早い方の実行計画は、実際にバインドされた値でもって作成された実行計画に見えます。
> 
> PostgreSQL 9.1までは、問い合わせ計画の作成時にはバインド変数の値は使われません。 
> 
> 汎用的な問い合わせ計画が作成されます。
> 今回の場合、それがnested loopだったのでしょう。
> 
> PostgreSQL 9.2からは、次のように、バインド変数の値が使われるようになりました。 
> 
> そのため、9.2にアップグレードすることが解決方法の1つだと考えます。
> 可能であれば、おためしいただいた結果を共有いただけると幸いです。
> 
> http://www.postgresql.org/docs/current/static/release-9-2.html
> Allow the planner to generate custom plans for specific parameter values 
> even when using prepared statements (Tom Lane)
> In the past, a prepared statement always had a single "generic" plan that 
> was used for all parameter values, which was frequently much inferior to the 
> plans used for non-prepared statements containing explicit constant values. 
> Now, the planner attempts to generate custom plans for specific parameter 
> values. A generic plan will only be used after custom plans have repeatedly 
> proven to provide no benefit. This change should eliminate the performance 
> penalties formerly seen from use of prepared statements (including 
> non-dynamic statements in PL/pgSQL).
> 
> 
> > なので、SQLの早い遅いは、実際のBIND値を考慮された実行計画かどうかの違いで、 
> > 
> > あとはそれがどこから来ているのか?ということか思います。
> 
> たしかに、速かったときは、バインド変数が使われなかったものと思います。
> バインド変数が使われなかった理由はわかりません。
> アプリなのか、JDBCドライバなのか、それともサーバ側なのか。
> もしこれを追求する場合は、次の情報を共有してください。
> 
> ・サーバ側が原因かどうか
> サーバ側にバインド変数を含むSQL文が送られているかどうか、つまり、
> SQL文中に$1などが含まれるかどうかを見ます。
> auto_explainの出力か、log_min_duraton_statement=0で出力される
> サーバログ中のSQL文でよいと思います。
> 
> ・アプリかJDBCドライバか
> テストアプリのソースを見せてください。
> 
> 
> 以上です。
> 



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