insertAll 是直连数据库的轻量操作,仅拼接单条多值 INSERT 语句,无模型生命周期开销;saveAll 实为循环调用 save,触发验证、钩子、时间戳等完整流程,性能开销大。

因为 insertAll 绕过模型层,只拼一条 SQL;而 saveAll 每条数据都走完整模型生命周期——验证、事件、自动时间戳、字段映射、类型转换……这些在纯搬运场景全是冗余开销。
insertAll 是“直连数据库”的轻量操作
它不加载模型类,不初始化验证器,不触发 beforeInsert/afterInsert 钩子,也不检查 $schema 或自动填充 create_time。只是把二维数组按字段名拼成:
INSERT INTO user (name, email) VALUES ('a','a@x'), ('b','b@x')- 一次请求、一次解析、一次执行
- 内存占用低,启动快,无副作用
saveAll 表面是批量,实则是“循环语法糖”
在 ThinkPHP 6.x 中,saveAll 并不生成单条多值 INSERT,而是对每条数据调用一次 save(),相当于:
- new 模型实例(或复用)→ 触发验证 → 走自动完成 → 填充时间戳 → 构建 SQL → 执行
- 1000 条 = 1000 次模型初始化 + 1000 次 SQL 构建 + 1000 次数据库往返
- 即使加
['validate' => false],仍绕不开字段映射、钩子判断、连接管理等流程
关键性能差异点
- 网络 I/O:insertAll 1 次往返;saveAll 是 N 次往返,延迟叠加明显
- 内存压力:saveAll 持有 N 个模型对象引用,易触发 memory_limit exhausted
- SQL 日志:TP 默认记录每条 save 的日志,大批量时日志缓冲区暴涨
- MySQL 约束:saveAll 的 N 条独立 SQL 更容易触发 max_allowed_packet(单条虽小,但总连接负载高)
什么时候 saveAll 反而更合适
只有当你需要以下任意一项时才该用 saveAll:
立即学习“PHP免费学习笔记(深入)”;
- 字段需自动类型转换(如 json 字段序列化)
- 依赖模型的
autoWriteTimestamp或type映射 - 必须触发
before_insert事件做动态处理 - 要获取每条插入后的自增 ID(insertAll 不返回 ID 列表)



















