insert ignore 仅在存在唯一索引或主键冲突时跳过重复行,无索引则完全无效;它不比对字段值,依赖数据库约束,且复合索引需覆盖全部重复判断字段。

INSERT IGNORE 不是万能去重方案,它只在有唯一索引(UNIQUE 或 PRIMARY KEY)冲突时才跳过,没建索引就完全不生效。
为什么 INSERT IGNORE 没跳过重复数据?
根本原因是表缺少约束——INSERT IGNORE 依赖数据库层面的唯一性校验,不是靠比对字段值。
- 必须存在
UNIQUE索引或PRIMARY KEY,且冲突字段要落在该索引列上 - 比如想按
email去重,就得给email字段加UNIQUE:ALTER TABLE users ADD UNIQUE (email);
- 复合唯一索引也行,但插入语句里的字段顺序和索引定义顺序无关,只看值是否整体冲突
- 如果误建了普通索引(
INDEX),INSERT IGNORE完全无反应,会照常报错或插入重复行
INSERT IGNORE 和 REPLACE INTO 的关键区别
两者都处理唯一键冲突,但行为完全不同:前者静默丢弃,后者先删后插。
-
INSERT IGNORE:遇到冲突直接跳过整行,不报错,affected rows返回 0 -
REPLACE INTO:遇到冲突会先DELETE原记录,再INSERT新行——这会导致自增 ID 变化、触发器重复执行、外键级联影响 - 如果表有
ON DELETE CASCADE关系,REPLACE INTO可能意外删掉关联数据;INSERT IGNORE则完全规避这点 - 性能上,
REPLACE INTO是 delete + insert 两步,I/O 和锁开销更大
INSERT IGNORE 在批量插入中的实际表现
单条和多值 INSERT 都支持,但“跳过”粒度是按行,不是按字段。
- 写法示例:
INSERT IGNORE INTO users (id, name, email) VALUES (1, 'Alice', 'a@b.com'), (2, 'Bob', 'b@b.com');
- 如果第一行因
email冲突被忽略,第二行仍会尝试插入,不受影响 - 但要注意:事务中混合操作时,
INSERT IGNORE被跳过的行不会回滚其他已执行语句,它本身不产生错误,所以不会中断事务 - 无法知道哪一行被跳了——只能通过返回的
affected rows数判断有没有跳过,不能定位具体是哪条
真正容易被忽略的是:唯一索引必须覆盖你关心的“重复维度”。比如业务上认为 (user_id, category) 组合不能重复,那就得建复合唯一索引,而不是只给 user_id 加唯一。少一个字段,IGNORE 就失效。











