美文网首页
MySQL 主键id自增达到最大值引发的线上问题

MySQL 主键id自增达到最大值引发的线上问题

作者: ToufuDrago_c53f | 来源:发表于2020-11-17 11:58 被阅读0次

4年前的代码,在没有任何改动的情况下,突然就炸了。

一、问题出现与处理

  1. 有用户反馈,自己的数据有问题,触发条件时积分没有增加。
  2. 一开始以为是用户操作不正确导致的,线上也没什么告警消息,但以防万一,自己打开APP进行了尝试。
  3. 自己尝试后发现真的有问题,就联系了同事,然后打开电脑查看相关代码。这是四年前就编写的代码,这段时间没有人改动过,最近没有代码上线,也没有改动过缓存和数据库配置。
  4. 积分信息保存在一张统计表,使用insert on duplicate key update语句进行新增、修改。
  5. 这段时间所有的积分都添加到了同一个用户上。
  6. 结合4、5,猜想是不是表的自增id出了问题,一看,发现该表主键id的AUTO_INCREMENT已经达到最大值。
  7. 当下的解决方式是将id由int类型改为bigint,表中实际只有两千万数据,大概十几分钟可以改完。
  8. 因为代码中id字段是声明为int类型,直接将数据库的id改为bigint的话,程序会报错,所以需要先改代码,上线后才能改表。
  9. 代码顺利上线,改表成功后,通过流水表的记录将用户积分修复为正确数据。

二、关于主键id自增

对于insert、insert on duplicate key update、insert ignore语句,如果没有指定主键id字段值,就算没有插入记录,也会导致AUTO_INCREMENT递增。
那么,自增字段达到了最大值时,MySQL是怎么处理的呢?
对于普通二级索引的自增字段,MySQL不会报错,而是始终将自增字段设置为最大值。
对于主键、唯一索引的自增字段:

  • 如果是insert语句,会报唯一键冲突的错误。
  • 如果是insert on duplicate key update,所有insert on duplicate key update语句的update操作都会执行到id为该字段数据类型的最大值的记录上。
  • 如果是insert ignore,会返回rows affected = 0。

三、总结

  1. 开发时使用insert on duplicate key update或insert ignore时,需要考虑这条语句的执行频率高不高,每天可能会增长多少id。
  2. 如果预估的id增长速度很快,业务场景又允许的情况,可以考虑使用先select,再决定是insert还是update的方式。
  3. 如果预估的id增长速度很快,业务场景又一定要使用insert on duplicate key update或insert ignore时,可以把id字段类型设置为bigint,几乎不用担心id不够用。
  4. 了解MySQL的SQL执行逻辑,有时候还是挺有帮助的,例如这次线上问题,因为之前了解过主键id自增会产生的问题,所以在看到代码中的SQL再结合线上问题的现象,能够比较快的联想到主键id的问题,从开始排查问题到给出解决方案,大概用了10分多钟。

相关文章

网友评论

      本文标题:MySQL 主键id自增达到最大值引发的线上问题

      本文链接:https://www.haomeiwen.com/subject/prazbktx.html