Mysql 的自增主键达到最大值,怎么办

1、遇到的问题

Mysql 的自增主键达到最大值,会发生什么你知道吗?就在今天,我们线上就发生了这种问题!!!

他会发生异常,报错如下:

Duplicate entry '2147483647' for key 'PRIMARY'

org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [PRIMARY]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

insert 数据就会报错。

2、分析

总结来说这算是架构上的设计问题吧。先说一下我们目前暴露出来的俩问题:

① Mysql 的自增主键默认是 int 类型,4 个字节,一个字节 8 位,即如果是有符号的位的话,最大值就是(2^31)-1,也就是2147483647,基本也就能存储 20 亿数据。当数据达到千万上亿级别时,查询数据就会特别特别慢了,所以我们就采取了数据归档。这里是另外一个坑下面在介绍。应该根据业务数据量,分析数据的增长情况,提前规划进行分库分表,至少要保证每个表不超过千万级。这样才能保证查询效率。

② 这里说下上边提到的另外一个坑:我们的因为查询比较慢,对表做过几次数据归档,就是将数据写入一张表中,当数据量很大时,就定时将某个时间之前的数据写入另一个表中,这样做也是有一些坑的。

Mysql的 delete 并不会真正的删除磁盘空间,而只是标记相应的区域,在合适的时候还可以再利用。如果要真正腾出磁盘空间还必须使用 optimize table xxx 进行磁盘碎片处理,但是这个命令会在相应的库下产生一个很大的 #sql-xxx 文件,此文件的赠长速度特别快,要清除的表越大它的增长速度就越快,所以不能等磁盘已经快满了才想起来清理。

而且 optimize 命令会锁表,一般根据表的数据增长速度和删除等情况综合考虑决定 optimize 命令的执行频率。比如在访问量最小的时候一个月或者两个月执行一次。

3、解决办法

① 修改 id 字段类型,int 改为 bigint(太占空间了,一个bigint的存储大小为8字节) bigint 的大小是8个字节,一个字节 8 位,有符号的最大值就是 2 的 63 次方 -1。即 bigint 带符号的范围是 -9223372036854775808 到 9223372036854775807。无符号的范围是 0 到 18446744073709551615。

② 有能力还是分表,有效避免这个问题

③ 将 int 类型设置为无符号的可以扩大一倍

基于以上三种最好的处理方法还是分库分表。

4、临时解决方案

目前我们基于线上的临时解决方案是新建了一个同结构的表,业务数据走新表,查询兼容旧表

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值