Laravel大批量数据填充性能关键在策略而非版本:需绕过Eloquent直用DB::table()->insert()、分批200–1000行、禁用事件与查询日志、手动设时间戳,避免模型实例化与冗余开销。

Laravel 10 和 11 在数据库填充(Seeding)的大批量数据写入场景中,底层 Eloquent、工厂系统和查询构造器并无本质性性能差异。真正影响内存占用与执行速度的,不是框架主版本号,而是你选用的数据插入策略——尤其是是否绕过模型层、是否分批、是否禁用事件与日志。
下面从实操角度,直击关键优化点,不讲版本噱头,只说能落地的方案。
绕过 Eloquent 模型,用 DB::table()->insert() 批量写入
Eloquent 的每个 `create()` 或 `saveMany()` 都会实例化对象、触发事件、维护关系缓存、记录变更状态。10 万条数据可能创建 10 万个 `Question` 实例,内存轻松突破 512MB。✅ 正确做法:
- 用
Question::factory()->make()生成纯数组(不实例化模型) - 或直接用
fake()构造字段值,组装二维关联数组 - 调用
DB::table('questions')->insert($data)一次性插入整批
示例片段:
```php $questions = []; foreach ($terms as $term) { for ($i = 0; $i $term->id, 'title' => fake()->sentence(), 'created_at' => now(), 'updated_at' => now(), ]; } } DB::table('questions')->insert($questions); unset($questions); gc_collect_cycles(); ```分批控制大小,别迷信“越大越好”
批次太小(如每批 50 条),IO 次数多、开销分散;太大(如单批 5000 条),可能超 MySQL 的 `max_allowed_packet`,或撑爆 PHP 内存峰值。✅ 推荐区间:
- 纯 ID + 短文本字段 → 可试 1000–2000 行/批
- 含 JSON、长文本、富媒体外键 → 建议 200–500 行/批
- 生产环境首次运行,先设 300 测 memory_get_peak_usage(),再逐步调高
用循环而非 collect()->chunk() 更可控(避免中间数组拷贝):
```php for ($i = 0; $i insert($batch); } ```禁用非必要开销:事件、日志、时间戳自动管理
默认开启的模型事件、查询日志、自动时间戳填充,在批量写入时全是冗余负担。✅ 必做三件事:
-
Term::withoutEvents(fn () => ...)或全局Factory::disableModelEvents() -
DB::disableQueryLog()(开发环境可关,生产默认已关,但显式调用更保险) - 手动设置
created_at/updated_at,避免 Eloquent 自动补全逻辑
注意:`$model->timestamps = false` 对 `insert()` 无效,它只影响 `save()`;必须靠手动赋值或跳过模型层。
慎用 upsert(),除非真有唯一约束需求
`upsert()` 看似高级,但它要求表存在唯一索引(如 `term_id, title` 联合唯一),且在 Laravel 11 中才对 PostgreSQL 完整支持。MySQL 下若无唯一键,`upsert()` 会退化为普通 `insert()`,还多一层判断逻辑。✅ 判断标准:
- 是测试数据填充?→ 用
insert(),简单高效 - 是幂等同步任务(如定时同步商品)?→ 加唯一索引,再
upsert() - 不确定是否有重复?→ 先
select exists小范围校验,再决定走哪条路
不复杂但容易忽略



















