LaravelのSeederで、csvファイルから大量のデータを一括登録しようとしたところ、ある件数を超えたところで以下のエラーが発生しデータを登録することができなかった。
今回はこの問題の原因と解決法を紹介する。
兎にも角にもログを確認
Laravelのログファイルはstorage/logs/laravel.log
にあり、最新のログはファイルの最下部に記載されている。
記載されていたエラーメッセージ(一部抜粋)は次のとおり。
(PDOException(code: HY000): SQLSTATE[HY000]: General error: 7 number of parameters must be between 0 and 65535 at …
調べてみると、バインドするパラメータの数が上限の65535を超えているため発生するエラーのようだ。
使っていたSeederファイルでは、while文で全データをループし、一度すべてのデータを配列化してから一回のinsert
文でまとめて処理しようとしていたので、件数が多いと今回のように上限に引っかかってしまうのだ。
while (($data = fgetcsv($fp)) !== false) {
$insert_data[] = [
'product_code' => $data[0],
'product_name' => $data[1],
];
}
DB::table('product_masters')->insert($insert_data);
解決法
先ほどのSeederファイルを以下のように変更してみた。
while (($data = fgetcsv($fp)) !== false) {
$loop_index++;
$insert_data[] = [
'product_code' => $data[0],
'product_name' => $data[1],
];
if ($loop_index % 10000 === 0) {
DB::table('product_masters')->insert($insert_data);
$insert_data = [];
}
}
if ($insert_data) {
DB::table('product_masters')->insert($insert_data);
}
ループ回数が10,000の倍数に達する度に都度insert
を実行するようにした。
なお、この10,000という数字は挿入するデータのカラム数に応じて変更しなければいけないので注意。
例えばカラム数が10のデータの場合、10,000回ごとのinsert
だとバインドするパラメータの数は100,000となるのでオーバーフローしてしまう。
とりあえずこれで数万件以上の大量データをSeederから一括登録できるようになった。