web-dev-qa-db-ja.com

JDBCを使用して大きなテーブルを反復する最速の方法

Javaプログラムを作成して、テーブルの行をクリーンアップしてマージします。テーブルが大きく、約50万行あり、現在のソリューションの実行が非常に遅いです。最初にしたいこと行うことは、単にテーブルのすべての行を表すオブジェクトのメモリ内配列を取得することです。

  • 一度に1000行の増分を選択する
  • jDBCを使用して、次のSQLクエリで結果セットをフェッチするSELECT * FROM TABLE WHERE ID> 0 AND ID <1000
  • 結果のデータをメモリ内配列に追加する
  • 結果を追加するたびに、最大500,000、1000の増分でクエリを続行します。

これは長い道のりを歩んでいます。実際には、1000から2000の2番目の増分を超えていません。クエリが完了するまでに永遠にかかります(ただし、同じことをMySQLブラウザから直接実行すると、かなり高速です)。 JDBCを直接使用してからしばらく経ちました。より速い代替手段はありますか?

22
Ish

まず、メモリ内のテーブル全体が必要ですか? (可能であれば)更新/マージ/その他の行を選択することを検討する必要があります。テーブル全体が本当に必要な場合は、スクロール可能なResultSetの使用を検討してください。このように作成できます。

// make sure autocommit is off (postgres)
con.setAutoCommit(false);

Statement stmt = con.createStatement(
                   ResultSet.TYPE_SCROLL_INSENSITIVE, //or ResultSet.TYPE_FORWARD_ONLY
                   ResultSet.CONCUR_READ_ONLY);
ResultSet srs = stmt.executeQuery("select * from ...");

'absolute'および 'relative'メソッドを使用して、任意の行に移動できます。

22
pablochan

おそらく最適ではありませんが、ソリューションは1回限りのデータベースクリーンアップルーチンでは問題ないようです。このようなクエリを実行して結果を取得するのにそれほど長くはかからないはずです(1秒なので、数秒で問題ないでしょう)。考えられる問題-

  • ネットワーク(または少なくともmysqlへの接続)は非常に遅いですか?その場合は、mysqlボックスでローカルにプロセスを実行するか、またはより適切な接続を試すことができます。

  • それを引き起こしているテーブル構造に何かありますか?行ごとに10kのデータを引き下げますか? 200フィールド?インデックス付けされていない行に基づいて取得するID値を計算しますか?データをプルする、よりdbに適した方法を見つけることを試みることができます(たとえば、必要な列だけ、dbの集計値など)

2番目のインクリメントを実行していない場合、何かが本当に間違っている-効率的であるかどうかにかかわらず、実行中のJVMのメモリに2000行または20,000行をダンプする問題はないはずです。多分あなたはデータを冗長に、または非常に非効率的に保存していますか?

2
Steve B.

私を助けたのはStatement.setFetchSize(Integer.MIN_VALUE)です。私はこのアイデアを Jasonのブログ から得ました。これにより、実行時間が半分以上削減されました。消費されるメモリが劇的に減少しました(一度に1行しか読み込まれないため)。

ただし、このトリックはPreparedStatementでは機能しません。

2
Shashikant Kore