insert ignore仅对主键或唯一索引冲突生效,其他错误照常报错;未建对应约束则完全无效,必须用show create table确认索引存在且覆盖目标字段。

INSERT IGNORE 不是万能静默开关,它只对主键或唯一索引冲突生效,其他错误照常中断执行。
为什么 INSERT IGNORE 没跳过重复数据?
根本原因几乎总是:目标字段没建 PRIMARY KEY 或 UNIQUE 约束。MySQL 不会“智能比对整行”,只靠索引触发冲突检测。
- 用
SHOW CREATE TABLE your_table确认输出里真有UNIQUE KEY或PRIMARY KEY覆盖你要去重的列(比如想按email去重,但表里只有id是主键,email没加唯一索引,那INSERT IGNORE就完全无效) - 已有重复值时,
ALTER TABLE t ADD UNIQUE KEY uniq_email (email)会失败,得先DELETE或GROUP BY清理 - 复合唯一索引要完整匹配,比如索引是
(org_id, email),但插入时只给email值,约束不生效,INSERT IGNORE也跳不过
INSERT IGNORE 返回值怎么判断才靠谱?
mysql_affected_rows() 的返回值不是“成功/失败”二值判断,而是三种状态:
- 1:新插入一行(正常)
- 0:因唯一冲突被跳过(这是你期望的“忽略”行为)
-
-1:发生未被
IGNORE覆盖的错误,比如ERROR 1406(字段超长)、ERROR 1292(非法时间格式)、NOT NULL字段插了NULL
不能只写 if (affected > 0) 就认为数据进去了——0 才可能是你想要的结果,-1 才真出问题。更稳妥的做法是执行后立刻跑 SHOW WARNINGS,看有没有 Duplicate entry 'xxx' for key 'PRIMARY' 这类提示。
INSERT IGNORE 和 ON DUPLICATE KEY UPDATE 能混用吗?
不能。语法直接报错。有人误写成:
INSERT IGNORE INTO t (a,b) VALUES (1,2) ON DUPLICATE KEY UPDATE b=3;
这会触发 MySQL 的语法解析失败。二者语义互斥:
- 要“只新增、不覆盖、不报错”,就用
INSERT IGNORE - 要“存在则更新指定字段”,就用
INSERT ... ON DUPLICATE KEY UPDATE -
REPLACE INTO是删+插,会重置自增 ID、触发BEFORE DELETE和AFTER INSERT触发器,和IGNORE完全不同
批量插入时容易被忽略的副作用
INSERT IGNORE 在事务中看似安全,但有几个隐蔽点:
- 即使某行被忽略,
AUTO_INCREMENT值仍会 +1,长期运行可能导致 ID 稀疏甚至溢出 - 被忽略的语句仍算作已执行,不会回滚整条语句,但会影响
LAST_INSERT_ID()的返回值 - 如果用在
pandas.to_sql场景,别依赖if_exists='append'—— 它默认抛IntegrityError,必须配合原生INSERT IGNORE+method='multi'才有效
真正要小心的,从来不是“它没跳过”,而是“它跳过了,但你没意识到自增 ID 已经悄悄涨了一截”。











