- PR -

JDBCの処理速度

投稿者投稿内容
nori
会議室デビュー日: 2004/10/06
投稿数: 4
投稿日時: 2004-10-06 16:01
はじめまして、noriと申します。
JAVAで開発をはじめて一ヶ月未満の初心者ですがよろしくお願いします。

データベースを検索する処理で、処理速度が明らかに違う為困惑しています。
色々教えていただけると助かります。

処理内容:データベースを検索し結果をCSVファイルへ出力します。
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//ステートメントオブジェクトを生成
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(StrSQL);
ResultSetMetaData objRmd = rs.getMetaData();

StrCSV = "";
RecCount = 0;
int i = 0;
// 各カラムの内容を繰り返し出力
for (i = 1; i <= objRmd.getColumnCount(); i++) {
StrCSV = StrCSV + objRmd.getColumnName(i);
if (i < objRmd.getColumnCount()) {
StrCSV = StrCSV + Delimiter;
} else {
StrCSV = StrCSV + "";
}
}
StrCSV = StrCSV + LineSeparator;
// 検索された行数分ループ
while (rs.next()) {
RecCount = RecCount + 1;
// 各カラムの内容を繰り返し出力
for (i = 1; i <= objRmd.getColumnCount(); i++) {
StrCSV = StrCSV + rs.getString(i);
if (i < objRmd.getColumnCount()) {
StrCSV = StrCSV + Delimiter;
} else {
StrCSV = StrCSV + "";
}
}
System.out.println(RecCount);
StrCSV = StrCSV + LineSeparator;
} // end while
↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

この処理の「objRmd.getColumnCount();」の部分を
事前に宣言した変数で置き換えると極端に遅くなってしまいます。

int ColumnCount = objRmd.getColumnCount();

これは、どのような理由で遅くなってしまうのでしょうか?
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2004-10-06 16:21
JDBCドライバの実装によって違いがあるので、
どのDBで、どのドライバを使用しているか
きちんと明記しないと、的確な回答は難しいと思いますよ。

見た感じだと、
for (i = 1; i <= objRmd.getColumnCount(); i++) {
で例えばカラムが50個あると、50回objRmd.getColumnCount()が呼び出されます。
毎回カラム数を動的に取得する実装のJDBCドライバであれば
遅くなって当然だと思います。
焼きそば
ベテラン
会議室デビュー日: 2002/11/06
投稿数: 86
お住まい・勤務地: 東京
投稿日時: 2004-10-06 16:27
焼きそばです。

引用:

かつのりさんの書き込み (2004-10-06 16:21) より:

見た感じだと、
for (i = 1; i <= objRmd.getColumnCount(); i++) {
で例えばカラムが50個あると、50回objRmd.getColumnCount()が呼び出されます。
毎回カラム数を動的に取得する実装のJDBCドライバであれば
遅くなって当然だと思います。




noriさんの質問内容はまったく逆の意味じゃないですか?
objRmd.getColumnCount()を何度も書かないように
変数に代入したところ、処理が重くなったと読み取ったのですが。
Y.Murakamin
会議室デビュー日: 2003/07/03
投稿数: 15
お住まい・勤務地: 埼玉県
投稿日時: 2004-10-06 16:27
私もかつのりさんと同様な回答をしようと思ったのですが、よく見てみると
引用:

この処理の「objRmd.getColumnCount();」の部分を
事前に宣言した変数で置き換えると極端に遅くなってしまいます。


と書いてありますね。
ResultSetMetaData取得直後でカラム数を取得して、その変数を使い回すと遅くなるという認識でよろしいでしょうか?
Y.Murakamin
会議室デビュー日: 2003/07/03
投稿数: 15
お住まい・勤務地: 埼玉県
投稿日時: 2004-10-06 16:29
あ。焼きそばさんとかぶってしまいました
蛇足ですが、文字列連結には+を使うんじゃなくてStringBuffer#append()を使うと劇的にパフォーマンスがあがりますよ
nori
会議室デビュー日: 2004/10/06
投稿数: 4
投稿日時: 2004-10-06 16:35
みなさん、返答ありがとうございます。
言葉足らずで、混乱させてしまい失礼しました。
DB:Oracle8.0.5
ドライバracle.jdbc.driver.OracleDriver
の環境で開発しています。

【A】for (i = 1; i <= objRmd.getColumnCount(); i++) {
のように「objRmd.getColumnCount()」が記述されている部分を
【B】for (i = 1; i <= ColumnCount; i++)
というように変数を使うように置き換えます。

この処理速度を比較するとBよりAのほうが早いのです。
単純に考えるとBの方が早いように思うのですが何故でしょうか?
raystar
ぬし
会議室デビュー日: 2003/01/16
投稿数: 251
お住まい・勤務地: Tokyo/Japan
投稿日時: 2004-10-06 16:55
こんにちは。

実際にどのくらい遅いのでしょうか。

変数を使っている場合と, getColumnCount() を使っているループを
System.currentTimeMillis() で時間を計測していただくと
ボトルネックが見えてくるかもしれません。

パフォーマンス改善が見こめる場所は

1.Statementではなく、PreparedStatementを使うこと
2.文字列連結は StringBuffer#append(String) を使用すること
3.SQL自体が遅くないか再検証すること(実行計画はどうなっていますか?)

ご参考まで。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2004-10-06 17:08
あくまで予想ですが、コネクションがらみで

1回目はgetColumnCount()で試して「速い」
そのまま2回目はintで試すと、
前回のコネクションのゴミが残っていて「遅い」とか・・・

ちなみに同じコンディションで測定していますか?
intもgetColumnCountもDBサーバ再起動してからとか。

raystarさんも仰る通り、ループの中で時間測定して
コンソールにでも出力した方がいいかもしれませんね。

スキルアップ/キャリアアップ(JOB@IT)