几年前整理过一篇<Differences between MySQL AUTO_INCREMENT 5.7 VS 8.0>,记录了两个版本对于auto_increment列存储的差异,提到mysql 5.7是auto_increment存在内存,而8.0后是增加了持久化到基表,这里再记录一些2者在重启后的的差异及影响。
一、重启后AUTO_INCREMENT
重启后mysql 5.7的形为是人从表里现有的最大ID+1 赋值AUTO_INCREMENT,而mysql 8是从字典基表加载。那就存在一个问题,如下
insert into t () --auto_inc:1
insert into t() -- auto_inc2:
delete from t where id=2;
restart mysql
这种情况重启mysql后,2个版本auto_increment的值就不再相同。
二、参数innodb_autoinc_lock_mode
-- mysql 5.7
mysql> show variables like 'innodb_autoinc_lock_mode';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_autoinc_lock_mode | 1 |
+--------------------------+-------+
1 row in set (0.00 sec)
-- mysql 8
mysql> show variables like 'innodb_autoinc_lock_mode';
+--------------------------+-------+
| Variable_name | Value |
+--------------------------+-------+
| innodb_autoinc_lock_mode | 2 |
+--------------------------+-------+
1 row in set, 1 warning (0.00 sec)
Consecutive 模式:自增值在语句结束后才分配,保证自增序列连续,但并发性能较差
Interleaved 模式:自增值提前分配,支持高并发,但可能导致自增序列出现间隙
三、检查当前auto_increment值
-- mysql 5.7
mysql> CREATE TABLE t1 ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t1 (name) VALUES ('row4');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM t1;
+----+------+
| id | name |
+----+------+
| 1 | row4 |
+----+------+
1 row in set (0.00 sec)
mysql> SELECT table_schema,AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_NAME='t1';
+--------------+----------------+
| table_schema | AUTO_INCREMENT |
+--------------+----------------+
| anbob | 2 |
+--------------+----------------+
1 row in set (0.00 sec)
mysql> show create table t1;
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1 | CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> INSERT INTO t1 (name) VALUES ('row5');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT table_schema,AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_NAME='t1';
+--------------+----------------+
| table_schema | AUTO_INCREMENT |
+--------------+----------------+
| anbob | 3 |
+--------------+----------------+
1 row in set (0.00 sec)
-- mysql 8.0
mysql> CREATE TABLE t1 ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t1 (name) VALUES ('row4');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT table_schema,AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_NAME='t1';
+--------------+----------------+
| TABLE_SCHEMA | AUTO_INCREMENT |
+--------------+----------------+
| anbob | NULL |
| mysql | 2 |
+--------------+----------------+
2 rows in set (0.01 sec)
mysql> INSERT INTO t1 (name) VALUES ('row5');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT table_schema,AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_NAME='t1';
+--------------+----------------+
| TABLE_SCHEMA | AUTO_INCREMENT |
+--------------+----------------+
| anbob | NULL |
| mysql | 2 |
+--------------+----------------+
mysql> CREATE TABLE t1 ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) ) ENGINE=InnoDB;
Query OK, 0 rows affected (0.01 sec)
mysql> INSERT INTO t1 (name) VALUES ('row4');
Query OK, 1 row affected (0.01 sec)
mysql> SELECT table_schema,AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_NAME='t1';
+--------------+----------------+
| TABLE_SCHEMA | AUTO_INCREMENT |
+--------------+----------------+
| anbob | NULL |
| mysql | 2 |
+--------------+----------------+
2 rows in set (0.01 sec)
mysql> INSERT INTO t1 (name) VALUES ('row5');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT table_schema,AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_NAME='t1';
+--------------+----------------+
| TABLE_SCHEMA | AUTO_INCREMENT |
+--------------+----------------+
| anbob | NULL |
| mysql | 2 |
+--------------+----------------+
mysql> update t1 set id=100 where id=2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t1;
+-----+------+
| id | name |
+-----+------+
| 1 | row4 |
| 100 | row5 |
+-----+------+
2 rows in set (0.00 sec)
mysql> SELECT table_schema,AUTO_INCREMENT FROM information_schema.TABLES WHERE TABLE_NAME='t1';
+--------------+----------------+
| TABLE_SCHEMA | AUTO_INCREMENT |
+--------------+----------------+
| anbob | NULL |
| mysql | 2 |
+--------------+----------------+
2 rows in set (0.00 sec)
mysql> show create table t1;
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1 | CREATE TABLE `t1` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
Note: MYSQL 8的information_schema.TABLES.AUTO_INCREMENT的值刷新并不即时,可能是来自disk, 数据更新在memory, 刷新有延迟,但不确认更新时间, 可以使用show create table查看。
结论
| 维度 | MySQL 5.7 | MySQL 8.0 |
|---|---|---|
| 重启后 Auto_inc | 2(MAX+1=2) | 3(持久化恢复) |
| 重启后新插入 id | 2(复用空洞) | 3(不复用) |
| 计数器存储位置 | 仅内存 | 内存 + 系统表持久化 |
| innodb_autoinc_persist | 不支持 | 支持(默认 ON) |
| GAP复用策略 | 重启后复用 | 持久化序列优先,不复用 |
| 重启恢复来源 | 扫描表数据 | 持久化系统表 |
| information_schema 实时性 | 实时更新 | 存在延迟 |
| lock_mode 默认值 | 1(consecutive) | 2(interleaved) |
重启后获取auto_increment方式的影响
| 方面 | MySQL 5.7 | MySQL 8.0 |
|---|---|---|
| 重启恢复速度 | 慢(需扫描表) | 快(从系统表读取) |
| 大数据表重启 | 可能很慢 | 仍然很快 |
| 表数据损坏时 | 可能丢失自增值 | 可以恢复 |
| 并发性能 | 较差(consecutive 模式) | 好(interleaved 模式) |
| 自增序列连续性 | 较好(consecutive 模式) | 可能出现间隙(interleaved 模式) |