こんにちは。開発ブログ運営担当の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を読み込んでインポートするといった一括で処理したいという要望は多いと思います。
そうした時に少しでもパフォーマンスを良くして、
ユーザーに気持ちよく使ってもらえるようにしたいですね。