約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を使って構築するサービスでバルクインサートを使うケースはそんなに多くは無い気がする。