在数据库批量写入场景中,重复键冲突是常见问题,INSERT IGNORE和REPLACE是MySQL中处理这类问题的两个常用语法,二者的执行逻辑和适用场景存在明显差异,需要结合具体业务需求选择使用。
批量插入基础语法
SQL标准的批量插入语法格式如下,一次性可以插入多条数据,减少客户端和数据库的交互次数,提升写入效率:
-- 基础批量插入语法 INSERT INTO user_info (id, user_name, age) VALUES (1, '张三', 20), (2, '李四', 22), (3, '王五', 25);
如果上述语句中id是主键,且已经存在id为1的记录,执行时会直接抛出重复键错误,导致整个批量插入失败。
INSERT IGNORE处理重复键
INSERT IGNORE会在插入时忽略重复键错误,对于有重复主键或者唯一索引的记录,直接跳过不执行插入,已存在的记录保持不变,不存在的记录正常插入。
语法示例
-- 使用INSERT IGNORE批量插入,重复记录会被忽略 INSERT IGNORE INTO user_info (id, user_name, age) VALUES (1, '张三_new', 21), -- id=1已存在,该条被忽略 (4, '赵六', 23); -- id=4不存在,正常插入
执行上述语句后,user_info表中id=1的记录内容不变,新增id=4的记录。
适用场景
- 业务上允许重复数据直接丢弃,不需要更新已有记录内容
- 批量插入的数据中部分重复不影响整体业务流程
- 不需要保留重复记录的旧版本数据
REPLACE处理重复键
REPLACE的处理逻辑是先删除已有的重复记录,再插入新的记录,相当于对重复记录做覆盖更新,整个过程是原子操作。
语法示例
-- 使用REPLACE批量插入,重复记录会被删除后重新插入 REPLACE INTO user_info (id, user_name, age) VALUES (1, '张三_new', 21), -- id=1已存在,先删除旧记录再插入新记录 (5, '孙七', 24); -- id=5不存在,正常插入
执行上述语句后,user_info表中id=1的记录会被替换为新的内容,新增id=5的记录。
适用场景
- 业务上要求重复记录用新数据覆盖旧数据
- 需要保证插入的数据是最新版本,旧数据没有保留价值
- 表的自增主键不会因删除操作产生断层问题(如果id是自增且被删除,新插入的id会取当前最大自增值+1)
二者核心差异对比
通过以下维度可以清晰区分两个语法的不同:
| 对比维度 | INSERT IGNORE | REPLACE |
|---|---|---|
| 重复记录处理方式 | 直接跳过,不修改已有记录 | 先删除已有记录,再插入新记录 |
| 已有记录的自增ID变化 | 不变 | 如果表有自增主键,重复记录的自增ID会被重新生成 |
| 触发器影响 | 不会触发删除相关触发器 | 会触发删除、插入相关触发器 |
| 执行效率 | 更高,不需要执行删除操作 | 更低,需要额外执行删除操作 |
使用注意事项
两个语法都仅适用于MySQL数据库,其他数据库如PostgreSQL、Oracle没有完全相同的语法,需要使用ON CONFLICT等对应语法实现类似功能。
如果表中有除主键外的其他唯一索引,两个语法都会检测所有唯一索引的冲突情况,不仅仅是主键冲突。
使用REPLACE时需要确认表是否有级联删除关系,避免误删关联表数据。
代码示例:结合业务选择方案
假设我们有一个用户积分表,需要批量同步用户最新积分,重复的用户直接更新积分,不存在的用户新增:
-- 使用REPLACE实现积分更新,重复用户覆盖积分 REPLACE INTO user_score (user_id, score, update_time) VALUES (101, 150, NOW()), (102, 200, NOW()), (103, 180, NOW());
如果是批量导入用户基础信息,重复用户不需要更新,只需要导入新用户:
-- 使用INSERT IGNORE实现新用户导入,重复用户忽略 INSERT IGNORE INTO user_base (user_id, phone, register_time) VALUES (201, '13800001111', NOW()), (202, '13800002222', NOW()), (203, '13800003333', NOW());
SQL批量插入重复键处理INSERT_IGNOREREPLACE修改时间:2026-07-01 01:54:39