insert ignore仅在存在primary key或unique索引时跳过冲突行,不报错、不更新、不修改原数据;无对应索引则等同普通insert,且对字段超长、not null违例等错误仍报错中断。

INSERT IGNORE 会跳过冲突,不会改已有数据
当插入的记录与现有主键或唯一索引冲突时,INSERT IGNORE 直接丢弃该行,不报错、不写入、也不修改任何字段。它只做“存在就跳过”这一件事。
常见错误现象:Duplicate entry 'xxx' for key 'PRIMARY' 这类错误被静默吞掉,返回影响行为 0;但如果你依赖 mysql_affected_rows() 判断是否成功插入,得注意:返回 0 不代表失败,可能只是被忽略了。
- 只适用于有
PRIMARY KEY或UNIQUE索引的表,否则等同于普通INSERT - 字段缺失时,未指定列按默认值填充(如
NOT NULL列没给值会报错,即使用了IGNORE) - 不会触发
ON UPDATE时间戳自动更新(因为根本没执行 UPDATE)
REPLACE INTO 实质是 DELETE + INSERT
REPLACE INTO 看似是“替换”,实则是先删后插:只要新行在任意一个 PRIMARY KEY 或 UNIQUE 索引上与旧行冲突,就会把旧行整个删掉,再用新行完整插入。
关键影响:AUTO_INCREMENT 值会递增(哪怕只是替换),且所有未显式指定的字段会被设为默认值(不是保留原值)。比如原记录 id=1, name='Alice', email='a@b.com',你只写 REPLACE INTO t(id, name) VALUES(1, 'Bob'),那 email 会变成 NULL 或空字符串(取决于定义)。
- 必须同时拥有表的
INSERT和DELETE权限 - 返回的影响行数 = 删除行数 + 插入行数(替换一行返回 2,新增一行返回 1)
- binlog 中记录为
DELETE+INSERT(或UPDATE,取决于索引类型),对主从延迟和审计有实际影响
两者都不该用于需要保留部分旧字段的场景
如果目标是“冲突时只更新某些字段,其余保持不变”,INSERT IGNORE 和 REPLACE INTO 都不合适——前者不更新,后者全量覆盖。
正确做法是用 INSERT ... ON DUPLICATE KEY UPDATE。例如:
INSERT INTO user (id, name, last_login) VALUES (1, 'Tom', NOW()) ON DUPLICATE KEY UPDATE last_login = VALUES(last_login);
这样只有 last_login 被更新,name 等其他字段不受影响。
-
REPLACE INTO无法做到字段级更新,容易误清空非目标列 -
INSERT IGNORE完全不处理冲突,业务逻辑需自行兜底 - 三者性能差异明显:
INSERT IGNORE最轻量,REPLACE INTO因涉及删除+插入,I/O 和锁开销更大
没有主键或唯一索引时,两者都退化成普通 INSERT
这是最容易被忽略的前提:INSERT IGNORE 和 REPLACE INTO 的“冲突判断”完全依赖 PRIMARY KEY 或 UNIQUE 索引。如果表没建这类约束,它们的行为和 INSERT INTO 完全一致——直接插入,不管重复不重复。
后果很直接:表里会出现大量主键/业务键重复的数据,后续查询、去重、统计全乱套。
- 上线前务必检查表结构:
SHOW CREATE TABLE t;确认有且仅有一个能覆盖业务唯一性的索引 - 唯一索引字段允许
NULL时,多个NULL不视为冲突(MySQL 特性),这点常被误用 - 复合唯一索引下,只有全部列值都相同时才触发忽略或替换











