Laravel 5.5 Seeder执行过慢求助:批量关联数据填充优化
批量生成Hit测试数据的性能优化经验
我最近在给测试库准备仪表盘测试数据时,遇到了一个头疼的性能问题——需要生成25000条Hit数据,每条都得关联数据库里随机的Post,保证数据一致性。一开始的方案差点把我搞疯,跟大家唠唠踩坑和优化的过程:
最初的糟糕方案:Factory里每次查随机Post
最开始我把随机获取Post的逻辑直接写在了HitFactory的定义里,代码大概是这样:
// 慢到离谱的HitFactory.php public function definition() { return [ 'post_id' => Post::inRandomOrder()->first()->id, // 其他Hit字段... ]; }
然后在Seeder里调用Hit::factory(25000)->create();。结果你猜怎么着?生成几千条数据就花了好几个小时,进度条慢得像蜗牛爬!后来才反应过来:每生成一条Hit,就会发起一次数据库查询去捞随机Post,25000条数据就是25000次查询,数据库直接被这种高频小查询堵死了。
优化思路:把随机逻辑移到Seeder,一次性拉取数据
我立刻调整了思路:把获取随机Post的逻辑从Factory移到Seeder里,只执行一次查询,把所有可用的Post ID先拉到内存数组里,然后在Factory里直接从数组里随机取ID关联。优化后的代码是这样的:
Seeder层(HitSeeder.php)
public function run() { // 一次性拉取所有Post的ID到内存数组 $postIds = Post::pluck('id')->toArray(); // 批量生成Hit,每次从数组里随机取Post ID Hit::factory(25000)->create(function () use ($postIds) { return [ 'post_id' => $postIds[array_rand($postIds)], // 其他Hit字段... ]; }); }
Factory层(HitFactory.php)
可以简化成只处理基础字段,Post ID由Seeder传入:
public function definition() { return [ // 其他Hit字段,比如访问时间、IP等 'visited_at' => now()->subDays(rand(0, 30)), 'ip_address' => fake()->ipv4, ]; }
优化后的效果
改完之后,25000条Hit数据几分钟就生成完了,效率直接提升了几十倍!核心就是减少重复数据库查询——把需要复用的关联数据提前一次性拉取到内存,避免每条数据生成时都发起单独查询。
这种思路其实适用于所有批量生成测试数据的场景:尽量把重复的IO操作(比如数据库查询、API调用)放在批量逻辑外面,一次性完成,然后在内存里复用数据,能极大提升生成速度。
内容的提问来源于stack exchange,提问作者user101289
相关产品推荐
相关产品推荐

