header
HikariBlog
Webエンジニア向けブログ
バックエンド

【Java】負荷試験用に大量のデータを投入する!

add-big-data

今回はこのような質問をいただきました。

負荷試験用に大量のデータを投入する必要があるんだけどどうしたら良い?

大量のデータを投入するときは考えてからやらないと、かなり時間がかかってしまいます。

そこで今回はこちらの質問について解説していきます!

環境
  • Java 11
  • Play Framework 2.6
  • IntelliJ IDEA ULTIMATE 2019.2

ネイティブクエリを使おう!

最初はエンティティを使って1件ずつ登録する処理でやってみたのですが、単純計算で240時間かかりそうだったので修正…まぁそうなりますよね笑

そこでネイティブクエリを使って1つのクエリで10,000レコード登録するような処理に変更しました。

これで

30レコード/秒 → 10,000レコード/秒

くらいの変化がありました。

このとき使ったコードを残しておきます。

エンティティを使って1件ずつ登録!

ネイティブクエリを使って1つのクエリで10,000レコード登録!

ネイティブクエリを使って大量にデータを登録する処理!

追加したいレコード数分ループさせて、10,000回に1回コミットします。

10,000レコードを一括で登録するSQL文を作ってる感じです。

String query = "INSERT INTO table_name (column_name1 , column_name2, column_name3, column_name4) VALUES";
StringJoiner joiner = new StringJoiner(",");
for (double i = 1; i <= 8000000; i++) {
    joiner.add("( 'value1', 'value2', 'value3', 'value4' )");

    if (i % 10000 == 0) {
        System.out.println(i);
        String values = joiner.toString();

        Jpa.jpa.withTransaction(() -> {
            Jpa.em().createNativeQuery(query + values).executeUpdate();
        });

        joiner = new StringJoiner(",");
    }
}
  • 1行目でテーブルの情報を指定してください。
  • 3行目でループ回数を指定してください。
    ループ回数によって6行目の条件を変更したほうが良いと思います。
  • 4行目で追加する情報を指定してください。
    ユニークな値が必要な場合は i を使うことでユニークになります。
  • 10〜12行目はORMによって違うと思うので書き換えてください。
    トランザクションを張ってネイティブクエリ(query + values)を実行しています。

あとがき

私が実行したときは2回ほどメモリ不足で停止してしまいました。

800万回ループさせるのはさすがに無理がありますね…

何回かに分けて実行したり、停止したらその値からリスタートしたりする必要があるかもしれません。

やりやすいように設定したり、処理を書き換えてみたりしてみてください!