replace into会导致自增id暴增,因其本质是delete+insert操作,每次冲突都会删除旧行并插入新行,触发新自增值分配;主从复制下auto_increment不同步,易引发主从切换后重复键错误;多唯一索引还可能导致误删行。

REPLACE INTO 会暴涨自增 ID,因为它本质是 DELETE + INSERT,而 INSERT 必然消耗一个新 AUTO_INCREMENT 值。
REPLACE INTO 实际执行的是两步操作
MySQL 没有“原地替换”这回事。当你执行 REPLACE INTO users (uid, name) VALUES (123, 'Alice'),且 uid 是唯一索引时,MySQL 会:
- 先按
uid = 123找到匹配行,执行DELETE - 再执行
INSERT,此时即使没显式指定id字段,也会触发自增逻辑,分配下一个可用 ID
哪怕表里只有一条记录、你反复 REPLACE 同一 uid,AUTO_INCREMENT 值也会持续递增——因为每次都是新插入。
主从复制下 AUTO_INCREMENT 会不同步
在 ROW 格式 binlog 中,REPLACE INTO 在主库上生成的是 DELETE + INSERT 两条事件,但从库回放时:
-
DELETE会成功(数据存在) -
INSERT会触发自增,但**从库不会同步主库的AUTO_INCREMENT值更新** - 结果:主库
AUTO_INCREMENT = 1000,从库仍卡在100
一旦发生主从切换,新主库用旧的 AUTO_INCREMENT 值继续插入,立刻撞上已存在的 ID,报错 Error 1062: Duplicate entry 'xxx' for key 'PRIMARY'。
多个唯一索引会让问题更隐蔽
如果表有 UNIQUE KEY uid 和 UNIQUE KEY phone,那么:
-
REPLACE INTO ... VALUES (123, 'new@example.com', '138...')可能匹配到uid=123的行,也可能匹配到phone='138...'的另一行 - 只要任一唯一索引冲突,就触发 DELETE + INSERT —— 你根本不知道删的是哪条
- 更糟的是:若两条记录分别命中不同唯一键,REPLACE 可能意外删掉本不该动的行
这种非确定性行为,让自增 ID 暴涨和数据丢失同时发生,且难以复现和审计。
真正需要“存在则更新”的地方,别碰 REPLACE INTO。它不是语法糖,而是带副作用的显式删插指令。最容易被忽略的一点是:ON DUPLICATE KEY UPDATE 不改变 AUTO_INCREMENT,也不删行——而这点,在主从架构和长期运行的表里,往往比少写几个字重要得多。











