insert ignore 通过将主键或唯一键冲突降级为警告实现跳过重复插入,仅对primary key和unique约束生效,需预先建立对应索引,不触发删除或更新操作,且不影响已有数据。

INSERT IGNORE 为什么能跳过重复主键或唯一键冲突
INSERT IGNORE 的本质是把原本会报错的重复键冲突(ERROR 1062: Duplicate entry)降级为警告,让语句继续执行而不中断。它只对违反 PRIMARY KEY 或 UNIQUE 约束的情况生效,对其他错误(如字段类型不匹配、NOT NULL 违反)依然报错退出。
常见误用场景:表没建唯一索引,却指望 INSERT IGNORE 去重——这完全无效。必须先确认目标字段(比如 email 或 order_id)上有 UNIQUE 索引或为主键。
- 执行前务必检查索引:
SHOW INDEX FROM users WHERE Key_name = 'uk_email';
- 如果用复合唯一索引(如
(user_id, action_type)),重复必须同时满足两个字段才被忽略 -
INSERT IGNORE不会返回“影响行数=0”来明确提示跳过,需结合ROW_COUNT()判断是否真有新数据插入
INSERT IGNORE 和 REPLACE INTO 的关键区别
REPLACE INTO 遇到重复键时,会先 DELETE 原有行再 INSERT 新行;而 INSERT IGNORE 完全不改动已有数据。这意味着:
- 自增 ID 可能被浪费(
REPLACE触发新 ID 分配,IGNORE不触发) - 触发器行为不同:
REPLACE会触发BEFORE DELETE和BEFORE INSERT,IGNORE什么也不触发 - 外键级联操作只在
REPLACE中发生,IGNORE视为无操作 - 如果业务只要“存在就不更新”,选
INSERT IGNORE;如果要“存在就覆盖”,应考虑INSERT ... ON DUPLICATE KEY UPDATE而非REPLACE
INSERT IGNORE 在批量插入中的实际表现
对多行 INSERT IGNORE(如 INSERT IGNORE INTO t VALUES (1,'a'),(2,'b'),(1,'c');),MySQL 会逐行判断:第一行插入成功,第二行也成功,第三行因主键 1 已存在而被忽略。但整个语句仍算执行成功,ROW_COUNT() 返回实际插入的行数(本例为 2)。
- 遇到语法错误或类型转换失败(如向 INT 插入 'abc'),整条语句直接报错,不会部分执行
- 若开启事务,被忽略的行不产生 undo log,不影响事务一致性
- 高并发下,多个连接同时
INSERT IGNORE同一值,可能有微小窗口导致都插入成功(取决于加锁时机),严格去重要配合应用层或SELECT + INSERT加锁
容易被忽略的兼容性与日志影响
INSERT IGNORE 是 MySQL 特有语法,在 PostgreSQL 或 SQLite 中不支持,迁移时需重写。另外,它会影响二进制日志(binlog)内容:被忽略的行不会写入 binlog,从库也不会执行那部分,这点和 ON DUPLICATE KEY UPDATE 不同(后者会记录 UPDATE 操作)。
更隐蔽的问题是:如果用 STATEMENT 格式 binlog,且语句含函数(如 NOW()),被忽略的行虽不写入,但时间戳已生成,可能造成主从时间字段微小偏差。生产环境建议统一用 ROW 格式 binlog。











