はじめに
Laravelのseederで大量のcsvのデータを挿入する際に詰まったので対処方法について記述します。
csvのデータ量が10000行程度であれば以下のようなシンプルなseederでデータを挿入することが可能です。
シンプルなSeederの作成
Laravel Seederを作成する
php artisan make:seeder CsvSeeder
Seederの実装
CsvSeeder.pfp
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class CsvSeeder extends Seeder
{
public function run()
{
// CSVファイルのパス
$filePath = database_path('seeders/data.csv');
DB::transaction(function () use ($filePath) {
// CSVファイルを開く
if (($handle = fopen($filePath, 'r')) !== false) {
$header = fgetcsv($handle); // ヘッダー行を取得
while (($row = fgetcsv($handle)) !== false) {
$data = array_combine($header, $row);
// データベースに挿入
DB::table('users')->insert([
'name' => $data['name'],
'email' => $data['email'],
'age' => $data['age'],
'created_at' => now(),
'updated_at' => now(),
]);
}
fclose($handle); // ファイルを閉じる
}
});
}
}
Seederを実行する
php artisan db:seed --class=CsvSeeder
大量データをSeederで挿入する方法
挿入するcsvデータが大量にある場合、メモリ不足でエラーになる場合があります。
対策としては以下が考えられます。
PHPのメモリ制限を増やす
php.ini
ini_set('memory_limit', '512M');
バルククエリを使用し、データを分割処理をする
CsvSeeder.pfp
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class CsvSeeder extends Seeder
{
public function run()
{
// CSVファイルのパス
$filePath = database_path('seeders/data.csv');
// バッチサイズ(1回の挿入処理でまとめるレコード数)
$batchSize = 1000;
$batchData = [];
// トランザクション処理
try {
if (($handle = fopen($filePath, 'r')) !== false) {
$header = fgetcsv($handle); // ヘッダー行を取得
while (($row = fgetcsv($handle)) !== false) {
// ヘッダーと行データを組み合わせる
$data = array_combine($header, $row);
$batchData[] = [
'name' => $data['name'],
'email' => $data['email'],
'age' => (int)$data['age'],
'created_at' => now(),
'updated_at' => now(),
];
// バッチサイズに達したら挿入
if (count($batchData) >= $batchSize) {
DB::transaction(function () use (&$batchData) {
DB::table('users')->insert($batchData);
$batchData = []; // 挿入後にバッチデータをリセット
});
}
}
// 残りのデータを挿入
if (!empty($batchData)) {
DB::transaction(function () use (&$batchData) {
DB::table('users')->insert($batchData);
});
}
fclose($handle); // ファイルを閉じる
}
} catch (\Exception $e) {
Log::error("Error occurred while processing CSV: " . $e->getMessage());
}
}
}
上記対応に加えてcsvデータのバリデーションやエラーハンドリングなどを行うことでスムーズな対応が可能になります。