如何使用Laravel Eloquent优化关联大数据批量插入
优化Eloquent多关联批量插入的高效方案
你的问题我太熟悉了——嵌套循环加频繁的单条数据库查询,肯定会拖慢执行速度。咱们直接用批量插入把数据库操作次数砍到最少,同时保持代码简洁优雅,彻底解决超时问题。
核心思路
把原来多层嵌套的单条插入,改成三层批量插入的模式:
- 先批量创建所有
Evaluation(每个Study对应一条) - 再批量创建所有关联的
Question(每个Evaluation对应38条) - 最后批量创建所有关联的
Answer(每个Question对应4条)
同时用事务包裹整个流程,既保证数据一致性,又能进一步提升插入效率。
优化后的代码
use Illuminate\Support\Facades\DB; Study::chunk(50, function ($studies) use ($request, $questionData, $answerData) { DB::transaction(function () use ($studies, $request, $questionData, $answerData) { // 1. 批量生成并插入所有Evaluation数据 $evaluationEntries = $studies->map(function ($study) use ($request) { return [ 'study_id' => $study->id, 'questionnaire' => $request->questionnaire, 'description' => $request->description // 模型默认开启自动时间戳,created_at/updated_at会自动填充,无需手动添加 ]; })->toArray(); // createMany会返回所有创建好的Evaluation模型实例(包含自增id) $evaluations = Evaluation::createMany($evaluationEntries); // 2. 批量生成并插入所有关联的Question数据 $questionEntries = []; foreach ($evaluations as $evaluation) { foreach ($questionData as $qItem) { $questionEntries[] = array_merge( $qItem, ['evaluation_id' => $evaluation->id] ); } } $questions = Question::createMany($questionEntries); // 对应你的question()关联模型 // 3. 批量生成并插入所有关联的Answer数据 $answerEntries = []; foreach ($questions as $question) { foreach ($answerData as $aItem) { $answerEntries[] = array_merge( $aItem, ['question_id' => $question->id] ); } } Answer::createMany($answerEntries); // 对应你的answer()关联模型 }); });
为什么这能大幅提升效率?
- 砍断数据库交互次数:原来150个Study需要执行
150 + 150*38 + 150*38*4 = 28650次数据库操作,现在每个50条的chunk只需要3次,总共9次操作,性能提升非常明显。 - 事务优化:事务中的批量插入会合并提交,减少数据库的IO开销和锁竞争。
- 降低内存占用:原来的循环会为每个关联都创建单独的模型实例,现在批量处理只需要一次性生成数据数组,内存压力小很多。
额外注意事项
- 确保你的模型开启了自动时间戳(默认是开启的),如果手动关闭了,需要在数据数组中手动添加
created_at和updated_at字段。 - 如果
questionData或answerData中有需要动态计算的字段(比如当前时间),可以在构造数组时统一处理,不要在循环里重复计算。 - 如果数据量极大(比如上万条),可以进一步调小chunk的大小,或者用
insert代替createMany(insert不会创建模型实例,内存占用更低,但需要依赖自增主键的连续性来关联数据,适合无并发插入的场景)。
内容的提问来源于stack exchange,提问作者Rizky Irmawan
相关产品推荐
相关产品推荐

