应根据语义需求选择:单纯追加用 insert,去重更新用 upsert;但 upsert 依赖数据库唯一索引与驱动支持,MySQL 8.0.19+、PostgreSQL 可用,SQLite 部分支持,SQL Server 不支持。

用 upsert 还是 insert,取决于你是否需要「存在则更新、不存在则插入」的语义。如果只是单纯追加数据,insert 更快更轻量;如果要避免重复、保持唯一性且批量处理,upsert 是 Laravel 9+ 提供的正确选择——但它的行为和底层 SQL 有强绑定,不注意会 silently 失败。
upsert 的实际行为依赖数据库驱动支持
upsert 在 MySQL 和 PostgreSQL 中表现不同,SQLite 仅部分支持,SQL Server 完全不支持(Laravel 会退化为逐条 insert + update)。调用前必须确认你的数据库版本和驱动配置:
- MySQL 8.0.19+ 支持
INSERT ... ON DUPLICATE KEY UPDATE,Laravel 会自动映射 - PostgreSQL 需要
ON CONFLICT子句,且$uniqueBy参数必须对应表中已存在的UNIQUE或PRIMARY KEY约束字段 - 若指定的
$uniqueBy字段没有对应唯一索引,MySQL 会报错1062 Duplicate entry,PostgreSQL 直接抛出SQLSTATE[42703]: Undefined column
DB::table('users')->upsert(
[
['email' => 'a@example.com', 'name' => 'Alice', 'score' => 100],
['email' => 'b@example.com', 'name' => 'Bob', 'score' => 85],
],
['email'], // $uniqueBy:必须是数据库中已有 UNIQUE 约束的字段
['name', 'score'] // $updateColumns:只更新这些字段,其他字段(如 created_at)不会被 touch
);
insert 不做冲突检测,但大数据量时要注意内存与事务
insert 只负责批量写入,不查重、不更新。适合日志、埋点、导入原始数据等场景。问题在于:一次塞几万条容易 OOM 或触发 MySQL max_allowed_packet 限制。
网趣购物系统静态版支持网站一键静态生成,采用动态进度条模式生成静态,生成过程更加清晰明确,商品管理上增加淘宝数据包导入功能,与淘宝数据同步更新!采用领先的AJAX+XML相融技术,速度更快更高效!系统进行了大量的实用性更新,如优化核心算法、增加商品图片批量上传、谷歌地图浏览插入等,静态版独特的生成算法技术使静态生成过程可随意掌控,从而可以大大减轻服务器的负担,结合多种强大的SEO优化方式于一体,使
- 建议按
1000行分批,用循环 +DB::transaction()包裹 - 不要把整个 CSV 解析后一次性
array_chunk再传给insert,而应在文件流读取过程中边解析边插入 - 使用
DB::statement()手动拼接多值 INSERT(如INSERT INTO t VALUES (),(),()...)比 Eloquent 的insert()快 3–5 倍,但需自己处理 SQL 注入(务必用DB::raw()和参数绑定)
foreach (array_chunk($data, 1000) as $chunk) {
DB::table('events')->insert($chunk);
}
upsert 的 $updateColumns 参数不能包含主键或唯一键
这是最容易踩的坑:$updateColumns 列表里如果误写了 id 或 email(而 email 又在 $uniqueBy 里),PostgreSQL 会报 ON CONFLICT DO UPDATE command cannot affect row a second time,MySQL 则可能静默忽略更新或报错。Laravel 不校验这个逻辑,全靠开发者自查。
- 正确做法:$updateColumns 只放业务字段,比如
['status', 'updated_at'] - 时间戳字段要显式写进 $updateColumns,否则
updated_at不会自动更新 - 如果想让
updated_at自动设为当前时间,得配合DB::raw('NOW()')或在模型中启用timestamps并手动赋值
真正麻烦的不是语法,而是 upsert 背后那层数据库约束——没建好唯一索引,它就不是 upsert,只是个会崩的 insert。别跳过 php artisan migrate 里的 Schema::unique() 步骤。









