insert ignore仅在存在primary key或unique约束时对冲突行静默跳过并降级为警告,无对应索引则完全无效;它不比对字段值,只依赖索引触发冲突检测,其他错误(如字段超长、非法格式、not null违例)仍报错中断。

INSERT IGNORE 不会自动去重,它只在有唯一约束冲突时跳过整行——没建索引就完全无效,连 warning 都不会发。
为什么 INSERT IGNORE 没跳过重复数据?
根本原因不是 SQL 写错了,而是表上缺对应字段的唯一约束。
-
INSERT IGNORE不比对字段值,它依赖 MySQL 底层的唯一索引(UNIQUE或PRIMARY KEY)触发冲突检测 - 比如想按
email去重,但表里只有id是主键、email没加UNIQUE,那两条相同email的记录照样插入成功 - 用
SHOW CREATE TABLE your_table;查看输出,确认是否有UNIQUE KEY或PRIMARY KEY覆盖你要判重的字段 - 已有重复数据时,
ALTER TABLE t ADD UNIQUE (email);会失败,得先清理:DELETE FROM t WHERE email IN (SELECT email FROM t GROUP BY email HAVING COUNT(*) > 1) LIMIT 1;(再逐个处理)
INSERT IGNORE 只忽略哪类错误?
它只把 Duplicate entry 类错误降级为 warning,其他一切错误照常报错中断。
- 字段超长(
ERROR 1406)、非法时间(ERROR 1292)、NOT NULL插入NULL、类型不匹配、外键失败……全都不被忽略 - 执行完立刻跑
SHOW WARNINGS;,能看到类似Duplicate entry 'xxx' for key 'uniq_email'的提示,这是它真正起效的证据 -
mysql_affected_rows()返回0表示“因冲突被跳过”,返回-1才代表发生了未被忽略的错误
复合唯一索引怎么配才生效?
业务上常需要多个字段组合判重,比如 (user_id, event_type),这时必须建复合唯一索引,单字段索引没用。
- 建索引:
ALTER TABLE events ADD UNIQUE (user_id, event_type); - 插入语句字段顺序无关,只要值组合与索引列完全匹配就会触发跳过:
INSERT IGNORE INTO events (event_type, user_id) VALUES ('login', 123);同样生效 - 注意 NULL 的特殊性:MySQL 允许唯一索引中存在多个
NULL,所以含NULL的行不会被INSERT IGNORE判为重复 - 排序规则影响判重:若字段是
utf8mb4_unicode_ci,'A@B.COM'和'a@b.com'被视为重复;换成utf8mb4_bin就区分大小写
批量插入时容易被忽略的副作用
多值 INSERT IGNORE 中,某一行被跳过,其余行照常插入——但它不提供哪一行被跳了的信息。
- 事务中混合操作时,被跳过的行不会回滚已执行的其他语句,也不会中断事务
-
LAST_INSERT_ID()在跳过时不变,但成功插入时会更新,这点在自增 ID 场景下容易误判 - 别和
ON DUPLICATE KEY UPDATE混用:INSERT IGNORE ... ON DUPLICATE KEY UPDATE是语法错误,二者互斥 - 如果目标是“存在就更新部分字段”,直接用
INSERT ... ON DUPLICATE KEY UPDATE更可控,INSERT IGNORE只适合纯新增场景
INSERT IGNORE 就彻底失效。











