A classic MySQL face questions, the answer appears three times inversion

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/yangjianrong1985/article/details/102645382

This is the first study notes a 2137 article

 

640?wx_fmt=gif

  A few days ago we happened to see a face in the discussion questions, and the answer is not enough unity, I feel very interesting, here to do a reading, the whole process does have a few reversed.

640?wx_fmt=jpeg

 

 We first look at the title:

A table, which has ID auto-increment primary keys, when the insert 17 records, delete records Article 15, 16, and then restart MySQL, then Insert a record, this record ID is 18 or 15.

 

And behind some of the problems as a whole, is not difficult, are seemingly very basic question, but This question caught my attention because the purpose of the background of this question is too open, so the answer is not fixed, and this is why we need to keep learning in technical rigor.

 

First, this question as a whole, want to express MySQL for inclusion in self understanding.

According to the logic of our conventional understanding, ID increment should be 18, according to this logic is not how it should be 15, right?

 

But the answer right? Obviously not, we enter the first round of the reversal.

 

 

Indeed, for an auto-increment problem, and this is the old problem of MySQL inside of the often-criticized . If the node is restarted, the manner max (id) +1 to process the data from the column, in the case of multiple environmental history data archiving, if the main library restart, it may be inconsistent data situation, remember MySQL bug in many people leave a message, say ten years ago, the old problem, and how not to solve.

In OpenWorld above Percona CEO Peter also mentioned this issue again.

640?wx_fmt=jpeg

 

I carefully checked the history of this bug, coincidentally, this issue is raised by Peter decade ago, Time flies, it has not been repaired.

640?wx_fmt=jpeg

好的,按照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)

 

>>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 NULL AUTO_INCREMENT,	
  `name` varchar(30) DEFAULT NULL,	
  PRIMARY KEY (`id`)	
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8	
1 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 NULL AUTO_INCREMENT,	
  `name` varchar(30) DEFAULT NULL,	
  PRIMARY KEY (`id`)	
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8	
1 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 NULL AUTO_INCREMENT,	
  `name` varchar(30) DEFAULT NULL,	
  PRIMARY KEY (`id`)	
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8	
1 row in set (0.00 sec)

而InnoDB存储引擎的表test_innodb的自增列却变为了4

>>show create table test_innodb\G    	
*************************** 1. row ***************************	
       Table: test_innodb	
Create Table: CREATE TABLE `test_innodb` (	
  `id` int(11) NOT NULL AUTO_INCREMENT,	
  `name` varchar(30) DEFAULT NULL,	
  PRIMARY KEY (`id`)	
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

 

>>insert into test_innodb(name) values('ee');	
Query OK, 1 row affected (0.00 sec)	

	
>>insert into test_myisam(name) values('ee');      	
Query OK, 1 row affected (0.00 sec)

可以看到两张表的id列已经分道扬镳了。

>>select *from test_innodb;                  	
+----+------+	
| id | name |	
+----+------+	
|  1 | aa   |	
|  2 | bb   |	
|  3 | cc   |	
|  4 | ee   |	
+----+------+	
4 rows in set (0.00 sec)	

	
>>select *from test_myisam;                  	
+----+------+	
| id | name |	
+----+------+	
|  1 | aa   |	
|  2 | bb   |	
|  3 | cc   |	
|  6 | ee   |	
+----+------+	
4 rows in set (0.00 sec)

小结:对于MyISAM和InnoDB的表,因为存储引擎对于自增列的实现机制不同,ID值也可能会有所不同,对于InnoDB存储引擎的表,ID是按照max(id)+1的算法来计算的。640?wx_fmt=jpeg

 

但是这个答案对吗?显然不是,因为还是不够严谨,我们进入第三轮反转。

 

 

The question is not precise enough because the technology is evolving, this question been answered in MySQL 8.0, for additional information from the InnoDB, directly after the loss if power is likely to cause a cascade synchronization occurs between the data from the database problem, but after MySQL 8.0, this information is written to the shared table space, so after the restart service, or you can continue from this retroactive inclusion of ID to changing circumstances. 

Due to space limitations, because the test log is very similar, I'll just give the log after the test, which is an auto-increment situation after the database is restarted, you can see test_innodb and test_myisam the auto-increment is exactly the same.

mysql> show create table test_myisam\G	
*************************** 1. row ***************************	
       Table: test_myisam	
Create Table: CREATE TABLE `test_myisam` (	
  `id` int(11) NOT NULL AUTO_INCREMENT,	
  `name` varchar(30) DEFAULT NULL,	
  PRIMARY KEY (`id`)	
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci	
1 row in set (0.00 sec)	

	
mysql> show create table test_innodb\G   	
*************************** 1. row ***************************	
       Table: test_innodb	
Create Table: CREATE TABLE `test_innodb` (	
  `id` int(11) NOT NULL AUTO_INCREMENT,	
  `name` varchar(30) DEFAULT NULL,	
  PRIMARY KEY (`id`)	
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci	
1 row in set (0.00 sec)

We make a summary:

 

Before MySQL 8.0:

    1) If MyISAM table, after the database is restarted, the value of ID 18

    2) If the InnoDB table, after the database is restarted, the value of ID 15

In MySQL 8.0 beginning,

    1) If MyISAM table, after the database is restarted, the value of ID 18

    2) If the InnoDB table, after the database is restarted, the value of ID 18

 

It should be added here that for additional self-ID, may be used in the sys schema in MySQL 5.7 to effectively monitor, you can see the view schema_auto_increment_columns column values ​​determined for efficient overflow. 

More commendable it is that, if it is MySQL 5.7 version of the following, although not sys schema properties, but can be reused schema_auto_increment_columns view of the statement in MySQL 5.7, as well as column values ​​can overflow effective judgment. 

 

 

640?wx_fmt=jpeg

 

 

 

Guess you like

Origin blog.csdn.net/yangjianrong1985/article/details/102645382