INSERT IGNORE仅在存在PRIMARY KEY或UNIQUE约束时,对对应字段的重复冲突静默跳过并返回0,其他错误(如类型不匹配、超长、NULL插入NOT NULL字段)仍报错;无约束则完全无效。

INSERT IGNORE不是“智能去重”,它只在碰到主键或唯一索引冲突时把错误降级为警告,然后跳过当前行。没建唯一约束?它完全不起作用,连 warning 都不会发。
必须先有唯一索引,INSERT IGNORE 才生效
MySQL 不会主动比对整行数据是否重复,它只依赖 PRIMARY KEY 或 UNIQUE 约束触发冲突检测。比如你想按 email 去重,但表里只有 id 是主键、email 没加 UNIQUE,那插入两条相同 email 的记录,INSERT IGNORE 就跟普通 INSERT 一样照插不误。
- 检查方式:
SHOW CREATE TABLE your_table;看输出里有没有UNIQUE KEY或PRIMARY KEY覆盖你要去重的字段 - 补加唯一索引:
ALTER TABLE user ADD UNIQUE KEY uniq_email (email);(注意:已有重复值会导致建索引失败,得先清理) - 复合唯一索引也行,比如
(user_id, event_type),适合业务上组合判重的场景
INSERT IGNORE 只跳主键/唯一键冲突,其他错误照报
它不是万能静默开关。字段超长、类型不匹配、NOT NULL 字段插了 NULL、外键约束失败……这些都会让语句直接报错中断,不会跳过。
- 常见陷阱:字符串字段定义为
VARCHAR(10),但插入了 12 个字符 → 触发ERROR 1406,IGNORE无效 - 另一个坑:时间字段传了非法格式如
'2026-02-30'→ERROR 1292,照样中断 - 想确认到底哪类错误被忽略了?执行完后立刻跑
SHOW WARNINGS;,里面会列出所有被降级的冲突,比如Duplicate entry 'xxx' for key 'PRIMARY'
返回值和实际影响容易误判
mysql_affected_rows() 或 mysqli_affected_rows() 返回值不是简单的“成功/失败”标志:
-
1:新插入一行 -
0:因唯一冲突被跳过(这是你期望的“忽略”行为) -
-1:发生未被IGNORE覆盖的错误,比如上面说的字段超长
所以不能只写 if (affected > 0) 就认为“数据进去了”——0 也可能是正常跳过,-1 才真出问题。更稳妥的做法是结合 SHOW WARNINGS 和返回值判断。
别和 ON DUPLICATE KEY UPDATE 混用
INSERT IGNORE 和 ON DUPLICATE KEY UPDATE 是互斥语法,不能同时出现。有人会误写成:
INSERT IGNORE INTO t (a,b) VALUES (1,2) ON DUPLICATE KEY UPDATE b=3;
这会直接报语法错误。要更新就用后者,要纯跳过就用前者。另外,REPLACE INTO 是删+插,会改变自增 ID、触发 DELETE 相关的触发器,和 IGNORE 的语义完全不同。
真正容易被忽略的是:约束本身的设计粒度。比如用 UNIQUE(email) 去重,但业务上其实希望 (email, tenant_id) 组合唯一——这时候单建一个字段的唯一索引就失效了,必须上复合索引,否则 INSERT IGNORE 对同一 email 在不同租户下的重复插入毫无反应。











