您现在的位置是:亿华云 > 人工智能
一道经典的MySQL面试题,答案出现三次反转
亿华云2025-10-04 01:09:46【人工智能】4人已围观
简介前几天偶然看到大家在讨论一道面试题,而且答案也不够统一,我感觉蛮有意思,在此就做一个解读,整个过程中确实会有几处反转。我们先来看下题目:一张表,里面有ID自增主键,当insert了17条记录之后,删除
前几天偶然看到大家在讨论一道面试题,道经典的答案而且答案也不够统一,试题我感觉蛮有意思,出现次反在此就做一个解读,道经典的答案整个过程中确实会有几处反转。试题

我们先来看下题目:
一张表,出现次反里面有ID自增主键,道经典的答案当insert了17条记录之后,试题删除了第15,出现次反16,17条记录,再把MySQL重启,道经典的答案再Insert一条记录,试题这条记录的出现次反ID是18还是15.
和后面的一些题目整体来看,难度不大,道经典的答案都是试题一些看起来很基础的问题,但是出现次反这道题目引起了我的注意,因为这道题目的背景过于开放,所以答案也是不固定的,而这也是亿华云计算我们在技术学习中需要保持的严谨态度。
首先这道题整体来看,想表达的是对于MySQL中自增列的理解。
按照我们常规理解的逻辑,ID自增,应该是18,按照这个逻辑怎么都不应该是15吧?
但是这个答案对吗?显然不是,我们进入第一轮反转。
确实,对于自增列的问题,这个是MySQL里面饱受诟病的老问题了。如果节点重启,会从数据列中按照max(id)+1的方式来处理,在多环境历史数据归档的情况下,如果主库重启,很可能会出现数据不一致的情况,记得在MySQL bug中很多人留言,说十多年前的亿华云老问题了,怎么还不解决。
而在OpenWorld上面Percona CEO Peter也再次提到了这个问题。

我认真查了一下这个bug的历史,巧合的是,这个问题是Peter在十几年前提出的,时光荏苒,一直没有修复。

好的,按照MySQL bug的思路来理解,答案应该是15了。
但是这个答案对吗?显然不是,我们进入第二轮反转。
这个题目的背景是不够清晰的,这个表的存储引擎没有说是InnoDB还是MyISAM,所以存在不确定性,这么说的意义在于,云服务器自增列的信息在MyISAM和InnoDB中的维护逻辑是不大一样的,在MyISAM中是存储持久化在文件中的,当数据库重启之后,是可以通过持久化的信息持续对ID进行自增的,而InnoDB的自增列信息既不在.frm文件,也不在.ibd文件中,所以在此启动的时候会按照max(id)+1的算法进行修复。
所以如果是MyISAM,则答案应该是18,而如果是InnoDB,则答案是15。
我们可以综合对比,用一个小的测试来模拟复现,我们选择的是MySQL 5.7环境。
为了对比明显,我们创建两张表test_innodb和test_myisam,分别对应InnoDB和MyISAM存储引擎,来做同样的操作,看看重启后的差异情况。
>>create table test_innodb(id int primary key auto_increment,name varchar(30)) engine=innodb;>>create table test_myisam(id int primary key auto_increment,name varchar(30)) engine=myisam;插入几行数据,查看数据:
>>insert into test_innodb(name) values(aa),(bb),(cc);Query OK, 3 rows affected (0.00 sec)Records: 3 Duplicates: 0 Warnings: 0 >>insert into test_myisam(name) values(aa),(bb),(cc); Query OK, 3 rows affected (0.00 sec)Records: 3 Duplicates: 0 Warnings: 0查看两张表的数据情况,数据是完全一样。
>>select *from test_innodb;+----+------+| id | name |+----+------+| 1 | aa || 2| bb || 3 | cc |+----+------+3 rows in set (0.00 sec) >>select *from test_myisam;+----+------+| id | name |+----+------+| 1 | aa || 2| bb || 3 | cc |+----+------+3 rows in set (0.00 sec)在1,2,3的基础上,我们继续插入值为5,跳过id值为4。
>>insert into test_innodb(id,name) values(5,ee);Query OK, 1 row affected (0.00 sec) >>insert into test_myisam(id,name) values(5,ee); Query OK, 1 row affected (0.00 sec)此时查看test_innodb自增列已经开始增长,值为6。
>>show create table test_innodb\G CREATE TABLE `test_innodb` ( `id` int(11) NOT AUTO_INCREMENT, `name` varchar(30) DEFAULT , PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf81 row in set (0.00 sec)删除id=5的记录
>>delete from test_innodb where id=5;Query OK, 1 row affected (0.01 sec)删除记录之后,自增列还是保持不变。
>>show create table test_innodb\G CREATE TABLE `test_innodb` ( `id` int(11) NOT AUTO_INCREMENT, `name` varchar(30) DEFAULT , PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf81 row in set (0.00 sec)同理test_myisam也做同样的测试,结果是完全一样的,在此略过日志。
我们停止数据库
>>shutdown;Query OK, 0 rows affected (0.00 sec)重启数据库
#mysqld_safe --defaults-file=/data/mysql_5723/my.cnf &此时查看test_innodb和test_myisam的自增列就开始出现差异了。
MyISAM存储引擎的表test_myisam的自增列还是不变,为6。
>>show create table test_myisam\G CREATE TABLE `test_myisam` ( `id` int(11) NOT AUTO_INCREMENT, `name` varchar(30) DEFAULT , PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf81 row in set (0.00 sec)而InnoDB存储引擎的表test_innodb的自增列却变为了4。
>>show create table test_innodb\G很赞哦!(896)
上一篇: 二、如何选择合适的域名
下一篇: 公司和个人选域名方法一样吗?有什么不同?
相关文章
- 付款完成后,您只需耐心等待,如果您注册成功,系统会提示您。这里需要注意的是,域名是一个即时产品,只有在最终付款成功时才能预订,注册成功后不能更改。
- 超全的数据库建表/SQL/索引规范,适合贴在工位上!
- 域名的价值有哪些呢?
- 警惕:小聚说说二手域名交易常见的陷阱!
- 2016年1月1日:注册价格将降至每年7欧元。
- Splunk 系列之 Splunk 安装部署篇
- MySQL流转工具Maxwell的代码改造和优化小结
- PyPy是不是真的比Python快?
- 在数以亿计的网站中,我们应该抓住每一个可能带来宣传的机会,域名可以带有企业的名字,一般可以使用汉语拼音或者英语单词或者是相关缩写的形式,只要用户记住了你企业的名字,就能很容易的打出你的网站域名,同样的,记住了网站域名也能很快的记住你公司的名字。
- 建议收藏备查!MySQL常见错误代码说明