こんにちは。開発ブログ運営担当のktです。
JDBCのバッチ更新を利用したことがありますか?
データベースへの送信回数を減らすことでパフォーマンスアップさせる方法ですが、
以前紹介したWITH句と同じで利用したことがない人が意外と周りにいます。
今回はバッチ更新を利用する方法を紹介します。
前提
画面から入力されたデータやCSVファイルから一括で読み込んだデータを、
パラメータが違うだけで同じinsert文やupdate文で複数レコードを更新することがあると思います。
[従業員No]、[名前]のカラムを持つ【従業員テーブル】に、
従業員Listの件数分insertする場合を例に説明したいと思います。
バッチ更新を利用しないパターン
PreparedStatementでパラメータを設定してexecuteUpdateメソッドをfor文で繰り返し実行します。
executeUpdateを実行するたびデータベースとの通信が発生します。
String sql = "insert into 従業員テーブル (従業員No, 名前) values (?, ?)";
PreparedStatement statement = connection.prepareStatement(sql);
for (従業員Bean bean : 従業員List) {
statement.setString(1, bean.get従業員No);
statement.setString(2, bean.get名前);
statement.executeUpdate();
}
※connectionのクローズや例外処理等は省略しています。
バッチ更新を利用するパターン
addBatchメソッドで追加し、ある程度実行するSQL文が溜まったらexecuteBatchメソッドで実行します。
1回のデータベースとの通信で溜まっていたSQL文全てを実行するので、
通信のオーバーヘッドが少なくなりパフォーマンスがアップします。
String sql = "insert into 従業員テーブル (従業員No, 名前) values (?, ?)";
PreparedStatement statement = connection.prepareStatement(sql);
int cnt = 0;
int listCnt = 従業員List.size();
for (従業員Bean bean : 従業員List) {
statement.setString(1, bean.get従業員No);
statement.setString(2, bean.get名前);
statement.addBatch();
cnt++;
if (cnt % 100 == 0 || cnt == listCnt) {
statement.executeBatch();
}
}
まとめ
例では100件溜まるたびにexecuteBatchメソッドを実行するようにしています。
溜めすぎても逆にパフォーマンスが悪くなる場合があるようです。
下記サイトで検証してくれています。
こういったまとめてSQLを実行する方法は、
MyBatis等のO/Rマッパーにも用意されています。
一括申請や一括承認といったワークフロー系のシステムや、
CSVを読み込んでインポートするといった一括で処理したいという要望は多いと思います。
そうした時に少しでもパフォーマンスを良くして、
ユーザーに気持ちよく使ってもらえるようにしたいですね。