insertall 是真批量插入,只发一次sql请求,不走模型逻辑;saveall 是伪批量,循环执行n次单条save,触发验证、时间戳、钩子等完整模型流程。

ThinkPHP 中 saveAll 和 insertAll 表面都支持“一次传多条”,但底层机制、适用场景和风险点完全不同。选错不仅慢,还容易报错、丢数据、爆内存。
底层执行方式不同
insertAll 是真批量插入:直接拼成一条 SQL,比如 INSERT INTO user (name, email) VALUES ('a','a@x'), ('b','b@x'),只发一次数据库请求。
saveAll 是伪批量:本质是循环调用单条 save(),N 条数据 = N 次 INSERT 查询,哪怕只插 100 条,也走 100 次数据库交互。
是否走模型逻辑
saveAll 走完整模型流程,会触发:
- 验证器(默认开启,可关)
- 自动时间戳(create_time 等字段自动填充)
- beforeInsert/afterSave 等钩子事件
- JSON 字段序列化、类型转换、字段映射检查
insertAll 完全绕过模型:
- 不校验数据格式,字段名必须和数据库列名严格一致
- 不自动写入时间戳,需手动塞进每条数据里,如 'create_time' => date('Y-m-d H:i:s')
- 不触发任何事件,也不做类型处理
性能与稳定性差异
insertAll 更快更稳:
- 内存占用低,适合导入几万条日志、同步数据等场景
- 支持分批参数(如 insertAll($data, 400)),自动切片执行
- 返回总影响行数(int),不返回 ID 列表
saveAll 容易出问题:
- 数据量稍大(如超 500 条)就可能触发 max_allowed_packet 错误或超时
- 即使加 ['validate' => false],仍要初始化模型对象,开销远高于 insertAll
- 返回值不稳定:自增主键返回 ID 数组,其他情况只返回 true/false
怎么选:看你要不要模型能力
用 insertAll 如果:
- 只是把干净数据快速写进表里(如后台导入、定时同步)
- 不需要验证、不关心事件、不依赖自动时间戳
- 数据量较大(>200 条),或对性能、内存敏感
用 saveAll 如果:
- 数据来自前端表单,字段不统一,需要验证和自动填充
- 必须触发 beforeInsert 等钩子做业务逻辑
- 数据量小(≤100 条),且已确认关闭验证或数据可信
别用 addAll——它是 TP3.2 的旧方法,TP5+ 已废弃。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











