web-dev-qa-db-ja.com

JDBC ResultSetをArrayListとして取得するにはどうすればよいですか?

大量のID(整数)を取得するためのクエリを実行しています。 ResultSetを何百万回も繰り返して、すべてを1つずつArrayListにコピーする代わりに、すべてをArrayListとして単純に取得する方法はありますか?

基礎となる実装がキャッシュのものである可能性があるため、ResultSetが繰り返されることになっていることを理解していますが、私の状況では、すべてのIDがすぐに必要です。 FetchSizeを大きな数値に設定できることはわかっていますが、それでもIDを1つずつ取得する必要があります。

明確化:これを実行したい理由はパフォーマンスです。プロファイリングは、ResultSet.next()、ResultSet.getInt()、およびArrayList.add()を何百万回も実行するのにかなりの時間がかかることを示しています。データベース(Javaで記述されたH2を使用しています)にはおそらくメモリ内のどこかに配列またはリストがあると思います。そのため、ResultSet反復インターフェイスを介さずに直接コピーする方法を探しています。 。

15
Deckard

Apache DbUtils ライブラリを使用すると、結果セットをマップのリストとして簡単に返すことができます。

public List query(String query) {
    List result = null;
    try {
        QueryRunner qrun = new QueryRunner();
        result = (List) qrun.query(connection, query, new MapListHandler());
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return result;
}
17
Mark

コードをメソッドに入れます。メソッドを呼び出すのはとても簡単です...

頭のてっぺんから:

public static List<Integer> readInts(
     PreparedStatement statement
) throws SQLException {
     ResultSet results = statement.executeQuery();
     try {
         assert results.getMetaData().getColumnCount() == 1;

         List<Integer> ints = new ArrayList<Integer>();
         while (results.next()) {
             ints.add(Integer.valueOf(results.getInt(1)));
         }
         return ints;
     } finally {
         results.close();
     }
}

次に、それを次のように呼び出します。

List<Integer> ids = readInts(myStatemnet);

完了。

問題のパフォーマンスが低い場合は、ステートメントを実行する前にステートメントを調整してください。

Java.sql.Statement.setFetchSize(int)

100、1000、10000、..を試してみてください。これにより、前述の速度低下の原因となる可能性のある不要なラウンドトリップを回避できます。

また、ArrayList.add()は、新しい配列を作成してそこにすべてのデータをコピーするため、内部配列のサイズを何度も変更する必要がある場合は遅くなる可能性があります。代わりにLinkedListを試してください。

5
Antonio