REPLACE INTO 导致主库自增ID递增而从库滞后,主从切换后因ID错位引发主键冲突;其本质是DELETE+INSERT操作触发主库AUTO_INCREMENT更新,但ROW复制下从库不执行INSERT故不更新该值。

它不会导致从库“暴增”,而是导致从库“滞后”——主库自增值变大,从库没变,主从切换后才暴露冲突。
REPLACE INTO 在主库上实际执行的是 DELETE + INSERT
当唯一索引(如 UNIQUE KEY c1)冲突时,REPLACE INTO 不是更新,而是先删旧行、再插新行。这个插入操作会触发主库的 AUTO_INCREMENT 值递增(比如从 100 → 102),哪怕你没显式指定 ID 字段。
- 主库 binlog 中记录的是逻辑上的
UPDATE事件(ROW 格式下为DELETE + INSERT行事件),但 MySQL 内部对自增计数器的更新只发生在执行 INSERT 阶段 - 从库回放时,如果是 ROW 模式,它只应用数据变更,不重新执行 INSERT 语句,因此不会调用
innodb_autoinc_lock_mode逻辑,AUTO_INCREMENT值保持不变 - 结果就是:主库
AUTO_INCREMENT = 102,从库仍是100
从库的 AUTO_INCREMENT 不同步是 ROW 复制的固有行为
MySQL 的复制机制决定了:只有显式的 INSERT(含 REPLACE INTO 触发的内部 INSERT)才会推进主库的自增计数器;而从库在 ROW 模式下仅还原数据行,不模拟语句执行过程。
-
innodb_autoinc_lock_mode = 1(默认)下,主库 INSERT 会预分配并持久化自增值,但从库不走这套流程 - 即使你查
information_schema.tables,从库显示的AUTO_INCREMENT值也始终停留在上次真正 INSERT(非 REPLACE 触发)后的值 - 这不是 bug,是设计使然:ROW 复制保证的是数据一致,不是“执行痕迹”一致
主从切换后报错 Duplicate entry 的真实原因
问题不在“暴增”,而在“错位”。从库升为主库后,它按自己的 AUTO_INCREMENT = 100 继续分配新 ID,但表里其实已有 ID=101、102 的行(由之前主库的 REPLACE INTO 插入并同步过来了)。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 第一次普通
INSERT尝试分配 ID=100 → 成功(因为该 ID 还没被占) - 第二次尝试分配 ID=101 → 报错
ERROR 1062 (23000): Duplicate entry '101' for key 'PRIMARY' - 根本矛盾是:从库的自增起点(100)小于它当前数据中已存在的最大 ID(102)
为什么 ON DUPLICATE KEY UPDATE 更安全
INSERT ... ON DUPLICATE KEY UPDATE 是原地更新,不触发 DELETE + INSERT,因此完全不推进 AUTO_INCREMENT 值。
- 主库执行
INSERT ... ON DUPLICATE KEY UPDATE冲突时,只改现有行,AUTO_INCREMENT不变 - 从库回放 UPDATE 事件,也不影响自增计数器
- 主从
AUTO_INCREMENT始终一致,切换无风险 - 注意:
REPLACE INTO返回的影响行数是 2(DELETE+INSERT),而ON DUPLICATE KEY UPDATE冲突时返回 2(实际是 1 UPDATE + 1 affected),但行为完全不同
最易被忽略的一点:这个不一致不会在日常同步中报错,也不会被监控轻易捕获。它安静地躺在 information_schema.tables 里,直到某次主从切换或手动 INSERT 才突然爆发。别等故障发生才查 AUTO_INCREMENT 值——尤其当你表上有唯一索引且业务大量用 REPLACE INTO 时。










