记一次MySQL AUTO_INCREMENT的故障

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 一、前言开发突然紧急的过来说,他们记录无法插入了,有报重复键错误ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'表名和数据都是采用测试数据,结果和生产的现象是一致的二、分析测试环境为percona server 5....

一、前言

开发突然紧急的过来说,他们记录无法插入了,有报重复键错误

ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'

表名和数据都是采用测试数据,结果和生产的现象是一致的

二、分析

测试环境为percona server 5.7.20。首先查看表数据和表结构,结果如下

mysql> select  * from t2 order by id desc limit 3;
+------------+------+------+
| id         | c1   | c2   |
+------------+------+------+
| 2147483647 |  101 |  101 |
|        100 |  100 |  100 |
|          4 |    4 |    4 |
+------------+------+------+
3 rows in set (0.00 sec)
mysql> show create table t2\G
*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `c1` int(11) DEFAULT NULL,
  `c2` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uniq_c1` (`c1`)
) ENGINE=InnoDB AUTO_INCREMENT=2147483647 DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

我们可以发现,其中id 是有符号的int,已经达到了int的最大值,但是这个表没有相应的时间字段来记录这个id=2147483647 的记录是何时插入或者更新的。和开发联系问有没有手动执行插入指定ID字段的,开发回复没有。拿到发送报错的时间点,把时间点之前的binlog 捞了下,都没找到有id=2147483647的插入记录。查找DDL变更记录,只找到了该表其他字段的变更,刚好在这个报错的时间点之前,但是没有修改auto_increment的值,一时间陷入了懵逼状态。

为了找到原因,豁出去了。用了九牛二虎之力,使用二分查找恢复了好多份备份,同时结合binlog ,终于确认这条记录的具体插入时间。意外的是,我发现这条记录插入的binlog是这样的

insert into t2(id,c1,c2) values(101,101,101) 也就是说,插入的时候的id 是101,并不是 2147483647,那又是为啥呢?

继续解析binlog,我发现了新大陆

update t2 set id=4147483647,c1=101,c2=101 where id=101;

通过dml平台的日志审计功能,我们找到了对应的开发,发现是开发误操作把主键更新了,然后溢出,id变成了2147483647

此时,表的ddl 的 auto_increment 还是等于101,并没有变成2147483647。后面的正常业务SQL进行insert产生的id正常产生,因此可以执行成功,直到我们做了一次DDL,加了以个字段,MySQL重新计算了auto_incremnt的值,变成了2147483647,新插入的SQL的自增值无法继续分配,主键冲突,业务开始报错,才发现了这个定时炸弹。

三、小结

MySQL如果在指定id 进行插入的时候,如果这个id大于表的自增值,那么MySQL会把表的自增值修改为这个id,并加1,但是如果我们把主键更新成更大的值,MySQL并不会把表的自增值修改为更新后的值,会埋下一颗定时炸弹,在某些情况下,如DDL,重启等之后,业务开始报错,会误认为DDL或者重启导致业务表的插入故障。

该问题在percona 5.6.24 和 percona 5.7.20均有出现,在MySQL 8.0.11 中表现正常。找到BUG发现2005年就有被提出,因为性能原因以及场景很少没有被修复

参考链接:

  1. https://dev.mysql.com/doc/refman/5.7/en/innodb-auto-increment-handling.html#innodb-auto-increment-initialization

  2. https://bugs.mysql.com/bug.php?id=12434

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
存储 SQL 关系型数据库
MySQL 5.7和 MySQL8.0 InnoDB auto_increment 初始化的区别
在MySQL 5.7及之前,自动递增计数器只存于内存,重启后需通过查询确定初始值。从MySQL 8.0开始,计数器变化时写入重做日志,检查点时保存至数据字典,确保重启后能基于持久化的最大值初始化,避免查询,增强连续性和一致性。[[MySQL参考手册, 3099页]](https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html)
|
8月前
|
关系型数据库 MySQL 数据库
MySQL中如何设置 auto_increment 重新计数 主键id从1开始
几句话解决 auto_increment 重新计数?
149 0
MySQL中如何设置 auto_increment 重新计数 主键id从1开始
|
10月前
|
SQL 关系型数据库 MySQL
MySQL AUTO_INCREMENT 原理解析
在关系型数据库MySQL中,AUTO_INCREMENT是数据库的一个属性,该属性使得在申明了AUTO_INCREMENT的列中可以自动生成唯一的递增值。本文详细介绍了在InnoDB及MyISAM引擎中AUTO_INCREMENT的使用原理及一些容易被忽略的问题。
|
关系型数据库 MySQL
MySQL 中 auto_increment 自动插入主键值
对于整数类型的主键,常搭配自增长 auto_increment 来使用。插入数据对应的字段不给值时,使用最大值+1!! 🌘下面进行演示~~🌒
MySQL 中 auto_increment 自动插入主键值
|
存储 SQL 关系型数据库
MySQL 主键自增 Auto Increment用法
MySQL 主键自增 Auto Increment用法
187 0
|
SQL 关系型数据库 MySQL
MySQL中ENGINE=InnoDB、AUTO_INCREMENT的意思
MySQL中ENGINE=InnoDB、AUTO_INCREMENT的意思
|
SQL 关系型数据库 MySQL
MySQL 使用 AUTO_INCREMENT 关键字
MySQL 使用 AUTO_INCREMENT 关键字
103 0
|
监控 算法 安全
MySQL:5.6 大事务show engine innodb status故障一例
MySQL:5.6 大事务show engine innodb status故障一例
173 0
MySQL:5.6 大事务show engine innodb status故障一例
|
MySQL 关系型数据库 PHP
mysql的auto_increment详解
转载http://blog.csdn.net/fwkjdaghappy1/article/details/7663331 auto_increment的基本特性 MySQL的中AUTO_INCREMENT类型的属性用于为一个表中记录自动生成ID功能,可在一定程度上代替Oracle,PostgreSQL等数据库中的sequence。
1558 0
|
SQL 关系型数据库 MySQL
记一次MySQL AUTO_INCREMENT的故障
MySQL如果在指定id 进行插入的时候,如果这个id大于表的自增值,那么MySQL会把表的自增值修改为这个id,并加1,但是如果我们把主键更新成更大的值,MySQL并不会把表的自增值修改为更新后的值,会埋下一颗定时炸弹,在某些情况下,如DDL,重启等之后,业务开始报错,会误认为DDL或者重启导致业务表的插入故障。
3283 0