Laravel9 バルクインサートを試してみた

約1,500件のレコードをinsertするのにcreate()を使用すると7秒くらいかかる。
あまり期待してなかったがバルクインサートを試してみたらかなり速かった。

バルクインサートとは

1レコード1insert文ではなく、1insert文で複数行をまとめてinsertする方法

■通常のinsert

INSERT INTO members(name, age) VALUES ('aaaa', 20);
INSERT INTO members(name, age) VALUES ('bbbb', 25);
INSERT INTO members(name, age) VALUES ('cccc', 30);

■バルクインサート

INSERT INTO members(name, age)
VALUES ('aaaa', 20),
       ('bbbb', 25), 
       ('cccc', 30);

検証結果

■前提条件

・1536件のレコードをinsert
・外部制約1つあり

■create()による通常のinsert

$start_time = microtime(true);

foreach($vectors as $idx => $vector){
    Vector::create([
        'parent_id' => $parent_id,
        'idx' => $idx,
        'vector' => $vector
    ]);
}

Log::debug("time: ".microtime(true) - $start_time);

結果

[2024-05-03 10:58:21] local.DEBUG: time: 7.351991891861  

1536件のinsertで約7秒もかかる。。。
Webサイトのページ更新中には行えない。

■バルクインサート

$timestamp = date('Y-m-d H:i:s');

$start_time = microtime(true);

$data = [];
foreach($vectors as $idx => $vector){
    $data[] = [
        'parent_id' => $parent_id,
        'idx' => $idx,
        'vector' => $vector,
        'created_at' => $timestamp,
        'updated_at' => $timestamp,
    ];
}

Vector::insert($data);

Log::debug("time: ".microtime(true) - $start_time);

バルクインサートでは、created_atとupdate_atカラムに自動でセットしてくれないので手動でセットする必要がある。

結果

[2024-05-03 11:11:16] local.DEBUG: time: 0.21577191352844  

速い!!約35倍速い!!

■created_atとupdated_atカラムを削除してバルクインサート
 insert先のテーブルではcreated_atとupdated_atカラムは必要なく少しでもパフォーマンスをあげたいので削除してみた。

$start_time = microtime(true);

$data = [];
foreach($vectors as $idx => $vector){
    $data[] = [
        'parent_id' => $parent_id,
        'idx' => $idx,
        'vector' => $vector,
    ];
}

Vector::insert($data);

Log::debug("time: ".microtime(true) - $start_time);

結果

[2024-05-03 11:04:53] local.DEBUG: time: 0.093423128128052  

なんと!通常のinsertと比べて70倍以上速くなった!!
100msかからないのならWebページ更新時にも処理しても良いと思う。

内部でいろんな処理をしているのだろうから速くないと思ったけど、created_atやupdated_atの値をセットしないなど極力バルクインサートのメリットを活かされている気がした。

このパフォーマンスなら使えると思う。
しかしLaravelを使って構築するサービスでバルクインサートを使うケースはそんなに多くは無い気がする。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です