首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 自增主鍵重複之謎:Row 格式複制 + REPLACE INTO + 唯一鍵觸發主備切換後主鍵衝突根因分析

     編輯:MySQL 資料庫相關知識

線上環境出現 Duplicate entry for key PRIMARY,經排查發現表內最大主鍵值大於自增計數器。人工調大 AUTO_INCREMENT 緊急恢復後,深入複現根因:Row 格式複制 + InnoDB + 自增主鍵 + 唯一鍵 + REPLACE INTO (LOAD DATA) 組合觸發主備切換後自增值不同步。

前置條件

  1. 複制格式:binlog_format = ROW
  2. 表引擎:InnoDB
  3. 表結構:含自增主鍵 + 唯一鍵
  4. 寫入方式:LOAD DATA INFILE ... REPLACE 或 REPLACE INTO

觸發鏈路

  1. 主庫:遇到唯一鍵衝突,REPLACE 內部轉為 DELETE + INSERT,自增計數器 +1(如 5→6),新行主鍵為 6。
  2. Binlog:Row 格式下,REPLACE 記錄為 UPDATE_ROWS_EVENT(更新現有行主鍵為 6),不包含自增計數器變更。
  3. 備庫:重放 UPDATE,將舊行主鍵從 2 改為 6,**但 UPDATE 不會更新自增計數器**,備庫自增值停留在 5。
  4. 主備切換:備庫升主,自增計數器為 5,表內最大主鍵為 6 → 下次 INSERT 產生主鍵 5 → 主鍵衝突。

完整複現腳本

-- 建表
CREATE TABLE test_autoinc (
  id INT AUTO_INCREMENT,
  c1 INT,
  c2 VARCHAR(100),
  PRIMARY KEY (id),
  UNIQUE KEY (c1)
) ENGINE=InnoDB;

-- 插入 5 筆,自增值變 6
INSERT INTO test_autoinc (c1,c2) VALUES (1,'abc'),(2,'abc'),(3,'abcdd'),(4,'abcdd'),(5,'abcdd');
-- SHOW CREATE TABLE → AUTO_INCREMENT=6

-- 主庫執行 REPLACE(c1=2 已存在)
REPLACE INTO test_autoinc (c1,c2) VALUES (2,'eeee');
-- 影響 2 行:DELETE id=2 + INSERT id=6
-- 主庫自增值變 7,備庫自增值仍為 6(UPDATE 不更新自增)

-- 主備切換後,新主庫自增值 6,表內最大 id=6 → 下次 INSERT 衝突

官方 Bug 與規避方案

已提交 Bug #73563。生產環境規避:

  • 避免在含唯一鍵的自增表使用 REPLACE INTO / LOAD DATA REPLACE,改用 INSERT ... ON DUPLICATE KEY UPDATE(Binlog 記錄為 WRITE_ROWS + UPDATE_ROWS,自增值同步正確)。
  • 若必須用 REPLACE,主備切換前手動同步自增值:ALTER TABLE t AUTO_INCREMENT = (SELECT MAX(id)+1 FROM t);。
  • 升級 MySQL 8.0.16+,官方修復了部分 Row 格式下自增同步問題(需驗證具體版本)。
核心教訓:Row 格式複制下,UPDATE 不傳播自增計數器。任何導致「主庫 DELETE+INSERT、備庫 UPDATE」的操作(REPLACE、LOAD DATA REPLACE、INSERT IGNORE 觸發唯一鍵衝突轉 UPDATE)均可能引發此問題。架構設計時務必評估複制格式與寫入模式的組合風險。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved