INSERT IGNORE没起作用的根本原因是表缺少PRIMARY KEY或UNIQUE索引约束,它仅依赖索引触发冲突检测,不比对字段值;无索引时行为等同普通INSERT,既不跳过也不报错。

INSERT IGNORE 不是“自动防重开关”,它只在表存在 PRIMARY KEY 或 UNIQUE 索引的前提下,对冲突行静默跳过;没建索引?它完全不生效,连 warning 都不会发。
为什么 INSERT IGNORE 没起作用
最常见原因:目标字段压根没有唯一约束。MySQL 不会逐行比对内容是否重复,它只依赖索引触发冲突检测。
- 用
SHOW CREATE TABLE your_table;查看输出里是否有UNIQUE KEY或PRIMARY KEY覆盖你要判重的字段(比如想按email去重,但只有id是主键、email没加UNIQUE,那两条相同email的记录照样能插进去) - 补加索引前,先清理已有重复值,否则
ALTER TABLE user ADD UNIQUE KEY uniq_email (email);会失败 - 复合唯一索引也行,比如
(user_id, event_type),适合组合判重场景
哪些错误会被 IGNORE,哪些不会
INSERT IGNORE 只把违反主键或唯一键的冲突降级为 warning,其他所有错误照常报错中断:
- 字段超长:如
VARCHAR(10)插入 12 个字符 → 触发ERROR 1406,IGNORE无效 - 非法时间格式:
'2026-02-30'→ERROR 1292,照样中断 - 向
NOT NULL字段插入NULL、类型不匹配、外键约束失败……全都不被IGNORE - 想确认到底忽略了什么?执行完立刻跑
SHOW WARNINGS;,里面会列出类似Duplicate entry 'xxx' for key 'PRIMARY'的提示
PHP 中怎么正确判断是否成功
别只看 mysqli_affected_rows() 返回值是否大于 0 —— 它返回 0 表示“因冲突被跳过”,这是正常行为;返回 -1 才代表发生了未被 IGNORE 覆盖的错误(比如字段超长)。
- 更稳妥的做法是:先检查返回值,再结合
SHOW WARNINGS判断 -
INSERT IGNORE和ON DUPLICATE KEY UPDATE互斥,不能混写,语法直接报错 - 事务中使用时,被忽略的语句仍算已执行,不会回滚整条语句,但会影响
LAST_INSERT_ID() - 批量插入建议单次不超过 1000 行,避免长事务锁表
真正容易被忽略的是:NULL 在唯一索引中通常不视为重复(标准 SQL 行为),所以多条 INSERT IGNORE 插入 email = NULL 可能成功多次,逻辑上却算“重复”。如果业务需要把 NULL 也当唯一值处理,得改用函数索引或应用层兜底。


















