唉,前几天刚好在公司茶水间碰到我们运维小王,他跟我吐槽,说他们有个老系统快上线十年了,最近业务激增,数据库里的那个自增ID,眼看就要撞上 int
最大值了。小王特别头疼,跑过来问我,哥,面试有个经典问题:“MySQL 自增ID超过int最大值咋办?”他怕到时候生产环境直接翻车,被老板逮住就凉了。
其实这个场景真的不是啥小概率,你看国内很多老项目,都喜欢表主键用 int
类型,MySQL 里的自增主键 AUTO_INCREMENT
默认类型也是 int(11)
,最大也就21亿多点(准确说是 2147483647),流量上来几年真够呛。
我当时正在泡茶,手上一杯铁观音,还差点没拿稳。想了一下就跟他说,你要真等撞线,业务那边新单插不进去了,SQL 报错啥的,整个服务都挂掉,出事基本没法挽救,用户体验直接负分。你说是不是,所以提前预警最重要。
聊到解决方案,其实最常见的就是把自增主键的类型从 int
升级到 bigint
,因为 bigint
最大可以到 9223372036854775807,真够一般公司用一辈子的,别说你们公司,马老板的业务也够撑很久。
不过实际操作,怎么升?你直接改表结构肯定不现实啊,有些几千万、上亿条数据,alter table
一跑就是几小时,搞不好线上直接锁表,业务全卡死,这锅你背不动。所以得分几步走:
先给表加个新字段,比如叫 id_bigint
,类型是 bigint unsigned
,千万记得 unsigned,否则你正好一半空间白给。
ALTER TABLE your_table ADD COLUMN id_bigint BIGINT UNSIGNED;
然后用脚本把老的 int 主键值同步到新字段:
UPDATE your_table SET id_bigint = id;
这一块你最好分批 update,别一次全跑爆了。
再接下来,你要把所有用到老 id 的地方,全都改成用新字段。这个事有点繁琐,什么业务代码、接口、甚至别的表的外键,都得挨个过一遍。我有次跟我们组的小李一起改了整整一晚上,到凌晨一点还在查漏补缺。
等所有地方都改好了,新的主键用上了,测试一遍没问题,再把老的 int 字段主键和自增都取消掉,然后把 bigint 字段升成主键+自增:
ALTER TABLE your_table DROP PRIMARY KEY, DROP COLUMN id, CHANGE COLUMN id_bigint id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY(id);
但其实很多公司会选择直接建新表,把历史数据全量迁移过去。这样有个好处,回滚啥的都容易,毕竟线上业务不能停啊。大不了用 pt-online-schema-change 这种工具在线改表,不过也有风险,别说我没提醒你。
我给小王举了个 Java 场景,他比较懂这个。你比如说你用 JPA 或 MyBatis 这种框架,实体类主键类型本来是 int 的,你也得全改成 long,不然取出来直接溢出。比如:
// 老代码
private Integer id;
// 新代码
private Long id;
不改,数据量大了就 GG。
对了,有朋友问那种雪花算法的分布式ID要不要用?其实这玩意儿也挺香的,你不用自增ID,改用全局唯一的 long 型ID,什么 leaf、twitter的 snowflake 实现都有。优点是不用担心自增撞线,缺点就是业务要接受长ID,不再是连续递增那种。
其实你们有时候还得注意一点,MySQL 的 int(11) 这个“11”不是数据范围,是显示宽度,跟最大值没关系,别被这个坑了。
最后小王问我要不要一开始就用 bigint?我说这看业务量,如果你才刚起步,量小,int 足够了,等真到快不够用再升,虽然听着有点鸵鸟,但现实就是这样,大公司有历史包袱,能不动就不动。要是真的新项目,建议直接上 bigint,省得后面折腾。

优网科技秉承"专业团队、品质服务" 的经营理念,诚信务实的服务了近万家客户,成为众多世界500强、集团和上市公司的长期合作伙伴!
优网科技成立于2001年,擅长网站建设、网站与各类业务系统深度整合,致力于提供完善的企业互联网解决方案。优网科技提供PC端网站建设(品牌展示型、官方门户型、营销商务型、电子商务型、信息门户型、微信小程序定制开发、移动端应用(手机站、APP开发)、微信定制开发(微信官网、微信商城、企业微信)等一系列互联网应用服务。