2011年8月19日

[pgsql-jp: 40890] Re:auto_explainの実行計画について

板垣さま

ご回答いただき、ありがとうございました。

下記、長文になってしまい、申し訳ありません。

>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;
}
}
}


}


以上、よろしくお願い致します。

投稿者 xml-rpc : 2011年8月19日 13:42
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/106230
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。