2

Java で ResultSet をループしています。テスト目的で、1 行あたり 17 列 (すべて文字列データ) の約 30 行を返します。StringBuilder を使用して結果から手動で XML 文字列を作成していますが、ループがこれらの反復を完了するのに文字通り約 36 秒かかります。

注: これは、データベースから XML を取得するための最良の方法ではなく、ResultSet から XML を取得するための最良の方法でさえないことを認識していますが、とにかくパフォーマンスが遅いことに興味があります。

更新:これまでの回答によると、次のことに対処する必要があります: クエリを実行する時間は 1 秒未満であり、これを絞り込むためにコードのすべてのセクションの前後に System.currentTimeMillis() を実行しました。36 秒は、以下のコード内に完全に含まれています。

ResultSetMetaData rsmeta = rset.getMetaData();
StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append("<?xml version=\"1.0\" ?><ROWSET>");
if(numColumns != 0){   
   while (rset.next()) {
      resultBuilder.append("<ROW>");
      for (int i = 0; i <= numColumns -1;i++) {
         columnName = rsmeta.getColumnName(i+1);
         resultBuilder.append("<");
         resultBuilder.append(columnName);
         resultBuilder.append(">");
         resultBuilder.append(rset.getString(i+1));
         resultBuilder.append("</");
         resultBuilder.append(columnName);
         resultBuilder.append(">");
      }
      resultBuilder.append("</ROW>");
      numRows += 1;
   }
}
else {
   stmt.close();
   wsConn.close();
   return "No Results";
}

更新:私が受け取った提案を考えると、このコードには、0.5 秒とほぼ同じ時間がかかります。

StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append("<?xml version=\"1.0\" ?><ROWSET>");
if(numColumns != 0){   
   while (rset.next()) {
      resultBuilder.append("<ROW>");
      for (int i = 0; i <= numColumns -1;i++) {
         //columnName = rsmeta.getColumnName(i+1);
         resultBuilder.append("<");
         resultBuilder.append("TestColumnName");
         resultBuilder.append(">");
         //resultBuilder.append(rset.getString(i+1));
         resultBuilder.append("TestData");
         resultBuilder.append("</");
         resultBuilder.append("TestColumnName");
         resultBuilder.append(">");
      }
      resultBuilder.append("</ROW>");
      numRows += 1;
   }
}
else {
   stmt.close();
   wsConn.close();
   return "No Results";
}  

他のすべてを排除して行った最後のテストは、 while テストを現実的な反復回数 (160、以前に行った小さなテストから返された最大行数) に置き換えることでした。ここで問題となるのは、このような速度低下の原因は、この結果セットについて何であるかということです。

while (numRows <= 160) {
// same as above
}

更新:タイトルが問題の方向性を反映していないため、この質問を終了します。

4

9 に答える 9

6

あなたのnote2はそれ自体で話すと思います。

時間は StringBuilder では失われませんが、別の場所で失われます...


columnName = rsmeta.getColumnName(i+1);

実装によっては、メタデータの読み取りが非常に遅くなる可能性があります。すべての結果セットに対して一度だけ読み取り、ループで再利用できます。


アップデート

前回の更新から、StringBuilder は問題外であり、問​​題は ResultSet にあります。質問のタイトルと与えられたすべての回答が、あなたの現在の関心事と一致していないように感じます.
この質問を閉じて、新しい関心のために新しい質問を開くことをお勧めします:-)

于 2010-02-02T15:16:04.590 に答える
5

データベースにアクセスしてデータを取得するのにかかる時間と比較して、StringBuilder がボトルネックであるとは思えません。単純な文字列連結を最適化しても実行時間が大幅に変わらないという事実は、これを裏付けています。

データベースへのアクセス方法を最適化する必要があります-DBへの接続の高速化、接続の圧縮など。

ただし、コードに 1 つのマイクロ最適化を提供できます。「<」のような単一文字の文字列を追加する代わりに、「<」のような文字を追加します。ただし、これは大きな違いはありません。

于 2010-02-02T15:16:54.377 に答える
3

StringBuilder私はそれがここの犯人であることを非常に疑っています. Javaはそれを広範囲に使用しており、私はそれを広範囲に使用しており、私自身の一種のJVM用に書き直しました。基本的に、毎秒数億の文字を常に食べることができます。

あなたの問題は、データベースへのアクセス自体にあると思います。クエリを実行して を取得してResultSetも、すべてのデータが取得され、管理しやすいメモリ表現に内部的に変換されているとは限りません。データベースの実装 (およびその JDBC ドライバー) によってはResultSet、およびメソッドが呼び出されたときに動的にフェッチされる多数の結果が保証される場合があります。ResultSet.next()ResultSet.getString()

取得next()getString()たデータをStringBuilder. それでも 36 秒かかる場合StringBuilderは無罪です (私はそう信じています)。

于 2010-02-02T16:46:46.320 に答える
2

問題はResultSet、データベースへの永続的なリンクがあり、呼び出されたときに詳細情報を取得することです。CachedRowSet(javadocはこちら)を調べることをお勧めします。すべてのデータをすぐにプルダウンし、それ以外の場合とまったく同じように機能しResultSetます。次に、データベース接続を閉じてから、データの解析を開始できます。それを試して、プロセスがスピードアップするかどうかを確認することをお勧めします。

于 2010-02-02T17:09:46.910 に答える
2

結果セットがどのように返されるかを確認してください。ステートメントには、ResultSetがデータを取り込む方法を変更できるメソッドがあります。

特に、見てください

于 2010-02-04T02:21:28.973 に答える
2

実際に getColumnName()、next()、および getValue() を使用して結果セットから情報を読み取るには、最初に結果をフェッチするよりもはるかに時間がかかることがよくあります。これは、スクロールできない結果セットの場合に特に当てはまります。

StringBuilder はメモリを指数関数的に (newSize = FACTOR*oldSize) 割り当てます。

これを実際にテストするには、単純にrsetrsmetaを同じメソッドを持つダミー オブジェクトに置き換えます。実際の行数に対して next() が true を返し、他のメソッドが実際の長さの文字列を返すようにします。

于 2010-02-02T16:15:50.373 に答える
1

ここでは、StringBuilder がリアルタイム シンクではない可能性があることに同意します。ただし、StringBuffer は、バッファが大きくなる (およびデフォルトのサイズを超える) と追加のスペースを割り当てる必要があるため、わずかに制限される場合があります。この提案はあなたの質問に対処しますが、繰り返しますが、彼らがあなたの問題に対処するとは思えません。

幸運を

于 2010-02-02T15:21:10.710 に答える
1

さまざまな通話を既定のデータに置き換えてみてください。たとえば、誰かがメタデータへのアクセスが原因であると示唆しています。置き換えてみてください:

columnName = rsmeta.getColumnName(i+1);

と:

columnName = "Column" + i;

ここで、i は int で、ループの前に 0 に設定し、ループを通じてインクリメントします。

于 2010-02-02T16:13:21.580 に答える
0

昨日も同様の問題が発生しました。MicrosoftSQLServer10で約170万レコードをクエリし、値を読み取るのに約50分かかりました。変更後; 約80秒...

私の問題は、使用されたjdbcドライバーでした。唯一の変更は、com.microsoft.sqlserver.jdbcバージョン1.2ドライバーからnet.sourceforge.jtdsバージョン1.2.2ドライバーに移行することでした。

于 2010-10-20T07:12:37.923 に答える