[pgsql-jp: 40890] Re: auto_explainの実行計画について
nozawakz @ nttdata.co.jp
nozawakz @ nttdata.co.jp
2011年 8月 19日 (金) 13:42:02 JST
板垣さま
ご回答いただき、ありがとうございました。
下記、長文になってしまい、申し訳ありません。
>auto_explain は実際に使用されたプランを出力するので、
>ご希望の事象を確認するためには十分利用できるはずです。
auto_explain.log_min_duration = 0
とし、実行計画をすることができました。
運用のシーンを考えますと、
再起動なしで時間を変えることができるので
欠かせないライブラリだと感じています。
>ただ、こちらについては ANALYZE で再プランニングされるかは疑問です。
>確かに ALTER TABLE 等、テーブル構成が変化するケースでは
>再プランニングされるのですが、8.3 以降であっても ANALYZE だけでは
>されないような気がします。
当方の試験手順に問題があるためか
再プランニングされておりました。
下記、試験内容となっております。
■試験内容
ANALYZEで実行計画が再プランニング(=最新化)されない可能性があり、
その場合レコード件数が増加するテーブルに対するSQLは性能劣化する恐れがある。
最新化されるかどうか確定情報がないため、実機(postgreSQL 8.4.4)で確認する
■試験結果&考察
実行計画は最新化されていたため、
板垣様の見解と異なるため、
当方の試験手順に問題があると思われる。
ただし、コネクションプーリングでなく、
sleep文で代用しているため、問題があるのでしょうか。
PostgreSQLとは直接関係のない質問になってしまうため、
もしも、ご存知でしたらご教授いただきたいです。
■試験内容詳細
①対象テーブル
postgres=# \d t_test02;
テーブル "public.t_test02"
カラム | 型 | 修飾語
--------+------------------------+--------------
a01 | character(12) | not null
a02 | character(15) |
a03 | character(3) |
a04 | integer |
a05 | character varying(24) |
a06 | character varying(255) |
a07 | integer |
a08 | character varying(384) |
a09 | date |
a10 | date |
a11 | character(7) |
a12 | character(7) |
a13 | character(7) |
a14 | integer |
a15 | integer |
a16 | character varying(384) |
a17 | date |
a18 | character(1) | デフォルト 0
a19 | date |
a20 | character varying(20) |
a21 | character varying(20) |
a22 | date |
a23 | date |
a24 | character(1) | デフォルト 0
インデックス:
"t_test02_pkey" PRIMARY KEY, btree (a01)
"idx_a02" btree (a07)
②SQL文
postgres=# \! date
2011年 8月 19日 金曜日 03:20:59 JST
postgres=# TRUNCATE t_test02;
TRUNCATE TABLE
postgres=# ANALYZE t_test02; ←①実行計画が最新ならこのSQLは実行計画がindex scanになる(0件にする)
ANALYZE
postgres=# \! date
2011年 8月 19日 金曜日 03:21:07 JST
postgres=#
postgres=#
postgres=#
postgres=#
postgres=# \! date
2011年 8月 19日 金曜日 03:21:15 JST
postgres=# INSERT INTO t_test02 (a01,a07) VALUES (1,1);
INSERT 0 1
postgres=# ANALYZE t_test02; ←②実行計画が最新ならこのSQLは実行計画がSeq Scanになる(1件にする)
ANALYZE
postgres=# \! date
2011年 8月 19日 金曜日 03:21:23 JST
postgres=#
postgres=#
postgres=#
postgres=# \! date
2011年 8月 19日 金曜日 03:21:46 JST
postgres=# TRUNCATE t_test02;
TRUNCATE TABLE
postgres=# delete from t_test02 where a01='1';
DELETE 0
postgres=# \COPY t_test02 from /home/test/a.txt
postgres=# ANALYZE t_test02; ←③実行計画が最新ならこのSQLは実行計画がindex scanになる(10万件にする)
ANALYZE
postgres=# \! date
2011年 8月 19日 金曜日 03:22:04 JST
③ログ(pg_log/postgresql.log)⇒auto_explain
2011-08-19 03:21:09 JST 28477 LOG: duration: 0.053 ms plan:
Index Scan using idx_a02 on t_test02 (cost=0.00..8.27 rows=1 width=1963)
Index Cond: (a07 = 1)
2011-08-19 03:21:39 JST 28477 LOG: duration: 0.045 ms plan:
Seq Scan on t_test02 (cost=0.00..1.01 rows=1 width=1963) ←実行計画が最新化されている!!
Filter: (a07 = 1)
2011-08-19 03:22:09 JST 28477 LOG: duration: 0.039 ms plan:
Index Scan using idx_a02 on t_test02 (cost=0.00..8.28 rows=1 width=122)
Index Cond: (a07 = 1)
【参考】
④JAVA側
-bash-3.1$ java PreparedTest
start SQL: 0 2011.08.19 at 03:21:09 JST
end SQL: 0 2011.08.19 at 03:21:09 JST
start SQL: 1 2011.08.19 at 03:21:39 JST
1
end SQL: 1 2011.08.19 at 03:21:39 JST
start SQL: 2 2011.08.19 at 03:22:09 JST
end SQL: 2 2011.08.19 at 03:22:09 JST
⑤JAVAソース
import java.sql.*;
import java.text.*;
import java.util.*;
public class PreparedTest {
public static void main(String[] args) {
PreparedTest preparedtest =new PreparedTest();
try {
preparedtest.selectPostgre();
} catch (Exception e) {
e.printStackTrace();
}
}
public void selectPostgre() throws Exception{
/* ユーザ名 */
String user = "postgres";
/* パスワード */
String pass = "nttdata";
/* サーバ名 */
String servername = "localhost";
/* データベース名 */
String dbname = "postgres";
ResultSet rset = null;
Connection conn = null;
Statement stmt = null;
try {
/* ドライバクラスのロード */
Class.forName ("org.postgresql.Driver");
/* Connectionの作成 */
conn = DriverManager.getConnection
("jdbc:postgresql://" + servername + ":5432/" + dbname,user,pass);
// ステートメントを作成
stmt = conn.createStatement();
// select文の場合
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM t_test02 WHERE a07 = ?;");
for (int i = 0; i <= 2; i++) {
java.util.Date date1 = new java.util.Date();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss z");
System.out.println("\nstart SQL: " + i + " "+ sdf1.format(date1)); //Dateオブジェクトを表示
pstmt.setInt(1, 1);
// Resultsetの作成
rset = pstmt.executeQuery();
// 取得したデータを表示します。
while (rset.next()) {
System.out.println(rset.getString(7));
}
java.util.Date date2 = new java.util.Date();
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss z");
System.out.println("end SQL: " + i + " " + sdf2.format(date2)); //Dateオブジェクトを表示
Thread.sleep(30000);
}
} catch (SQLException e) {
throw e;
} catch ( Exception e){
throw e;
} finally{
/* クローズ処理 */
if(conn != null){
conn.close();
conn = null;
}
if(stmt != null){
stmt.close();
stmt = null;
}
}
}
}
以上、よろしくお願い致します。
pgsql-jp メーリングリストの案内