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から一括登録できるようになった。