CREATE TABLE t1(id INT AUTO_INCREMENT, a INT, PRIMARY KEY (id)) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,2), (NULL,2), (NULL,2);
-- id: 1,2,3
DELETE FROM t1 WHERE id IN (2,3);
-- 僅剩 id=1
-- 重啟 MySQL 後
INSERT INTO t1 VALUES (NULL,2);
-- 新插入 id=2(預期應為 4)
核心問題:MySQL 重啟後,InnoDB 自增計數器回退,導致主鍵值重複使用。若存在歷史表 t1_history 已存 (2,2),新數據遷移時將違反主鍵約束。
AUTO_INCREMENT 存於 .frm 文件dict_table_struct.autoinc),不實時寫回 .frmSHOW CREATE TABLE 讀取的是內存值而非 .frmMySQL 重啟時,內存值丟失,.frm 值不準(偏小),採用:
SELECT MAX(id) + 1 FROM t1
此法導致已刪除的最大 ID 空洞被重複使用。
.MYI 文件頭(mi_state_info_write)mi_state_info_read)每次更新自增值同步寫 .frm,屬額外 I/O 操作,性能損耗大。
trx_id 僅對二級索引頁和 Insert Buffer 頁有效(MVCC)trx_id 始終為初始值 0,佔 8 字節,完美存放自增值新增全局參數 innodb_autoinc_persistent (ON/OFF)
sysbench 測試 (100 線程, 僅 INSERT):
OFF: TPS 22199, RT 2.25ms
ON: TPS 22003, RT 2.27ms
損耗 < 1%
新增 innodb_autoinc_persistent_interval(默認 1,即每次持久化)。設為 100 時,每 100 次 INSERT 持久化一次,值增加 100。
| 配置 | TPS | RT(ms) |
|---|---|---|
| OFF | 22199 | 2.25 |
| ON, interval=1 | 22003 | 2.27 |
| ON, interval=10 | 22069 | 2.26 |
| ON, interval=100 | 22209 | 2.25 |
[mysqld]
innodb_autoinc_persistent = ON # 必須在配置文件指定
# 動態 SET GLOBAL 重啟後失效,不會從根頁讀取
.frm 中的 AUTO_INCREMENT 對 InnoDB/MyISAM 均顯冗余,其他引擎未研究MAX(id)+1 需索引支撐,這解釋了「自增列必須包含在索引中」的強制要求;MyISAM 同樣要求或許是歷史兼容innodb_autoinc_lock_mode:控制自增值連續性,解決主備複制問題,與本文無關。