直接升级主键为BIGINT不能立刻解决问题,因InnoDB需重写整张表聚簇索引并更新所有二级索引,大表操作将导致长时间锁表、CPU飙升及从库延迟;外键依赖、应用层类型不匹配、缓存与日志链路未适配19位ID等均会引发线上故障。

直接改 BIGINT 并不能立刻解决问题,尤其是大表;真正卡住你的,是聚簇索引重建过程本身,不是类型声明。
为什么 ALTER COLUMN 到 BIGINT 会失败或卡住
很多人执行 ALTER TABLE t MODIFY id BIGINT UNSIGNED AUTO_INCREMENT; 后发现锁表超时、CPU 拉满、从库延迟飙升——这不是语句写错了,而是 InnoDB 在重写整张表的聚簇索引。
- INT → BIGINT 不是“元数据标记变更”,InnoDB 必须逐行读取、转换、重写所有数据页,同时更新所有二级索引中的主键引用
- 5000 万行以上、单行 > 1KB 的宽表,这个 DDL 可能持续数小时,期间写入完全阻塞
- MySQL 8.0 的
ALGORITHM=INSTANT对列类型变更无效(仅支持加/删列、改默认值等极少数操作) - 如果表有外键,且子表字段仍是
INT,ALTER 会直接报错:ERROR 1832 (HY000): Cannot change column 'id': used in a foreign key constraint
安全升级前必须完成的三件事
跳过任何一项,都可能在半夜触发主键冲突或服务中断。
- 查清所有依赖该主键的外键:运行
SELECT CONSTRAINT_NAME, TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE REFERENCED_TABLE_NAME = 'your_table' AND REFERENCED_COLUMN_NAME = 'id';,然后挨个确认子表字段类型 - 检查应用层变量类型:Java 项目里
Integer要全换成Long;Go 里int或int32得改int64;ORM 映射(如 MyBatis 的<result property="id" column="id"/>)也要同步改类型 - 验证缓存与日志链路:Redis 中以
id为 key 的缓存、ELK 里记录的 SQL 日志、监控系统中基于id的指标聚合,都要确认是否支持 19 位数字(JSON 默认会把BIGINT当成浮点截断)
AUTO_INCREMENT 值虚高但没真耗尽?先重置再升级
如果你看到 SHOW TABLE STATUS 返回的 Auto_increment 是 1000 万,而 SELECT MAX(id) 只有 500 万,说明存在大量删除导致的“空洞”。这时别急着升 BIGINT,先用重置缓解压力。
- 目标值必须严格大于当前
MAX(id),例如MAX(id) = 5000000,则执行ALTER TABLE your_table AUTO_INCREMENT = 5000001; - 这条语句不重写数据,只修改内存+字典中的计数器,毫秒级完成
- 它无法绕过字段类型上限(比如
INT已到 2147483647),但能买出几周时间做灰度迁移 - 注意:MySQL 5.7 及之前版本,重启后可能丢失该值(因未持久化到 .ibd),8.0+ 更可靠
真正要警惕的,是“改完就完事”的幻觉
改完类型、跑通 DDL、插入新数据返回了 19 位 ID,不代表问题结束。最容易被忽略的是二级索引膨胀和查询计划漂移:原本 id < 1000000 走索引范围扫描,现在因 BIGINT 字段变宽,B+ 树层级可能多一层,某些联合索引的区分度下降,EXPLAIN 显示的 rows 会突然翻倍。上线后务必盯紧慢查日志和 Buffer Pool 命中率。


















