MySQL:自增不连续的几种情况总结

自增实际上是单个表上的一个计数器,对于简单的insert语句来讲肯定都是每次+1的,但是对于批量就有可能预先分配一些。一旦抬升不会因为错误或者回滚而降低,简单总结一下常见的情况,

  • 事务回滚,计数器增加
  • 语句报错,计数器增加
  • 自己填充自增值,抬高计数器
  • 参数innodb_autoinc_lock_mode为2的时候(8.0默认),insert select 类似批量导入数据,可能导致自增浪费一部分,但是却避免了自增锁,类似
| 1198 | g    |
| 1199 | g    |
| 1200 | g    |  ->gap
| 1256 | g    |  ->gap
| 1257 | g    |

大概的算法为第一次申请1个,第二次申请2个,第三次申请4个 …每次为2的N次方,但是每次分配不能超过AUTO_INC_DEFAULT_NB_MAX(65535),也就是最大一次分配65535个自增。代码如下,

 nb_desired_values = AUTO_INC_DEFAULT_NB_ROWS * (1 << auto_inc_intervals_count);//每次左移1位,也就是2的auto_inc_intervals_count次方
 nb_desired_values = std::min(nb_desired_values, ulonglong(AUTO_INC_DEFAULT_NB_MAX));

但是值得注意的是,如果有大量insert on duplicate key update的语法,这种语法当插入唯一值的时候在本应该报错唯一键冲突的时候屏蔽报错,转走update流程,但是实际上报错是存在的因此自增也随之提升,当执行下一次插入的时候就会由于自增已经提升而导致很多无谓的gap,这实际上就是第2点。 replace语法也有类似的问题,replace的问题在于会如果触发update机会修改主键自增的值,导致gap。下面是insert on duplicate key update的测试(8.0版本),

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

mysql> insert into test123(name,a) values('g',1);
Query OK, 1 row affected (0.03 sec)

mysql> insert into test123(name,a) values('g',2);
Query OK, 1 row affected (0.01 sec)

mysql> insert into test123(name,a) values('g',3);
Query OK, 1 row affected (0.00 sec)

mysql> insert into test123(name,a) values('g',4);
Query OK, 1 row affected (0.05 sec)

mysql> insert into test123(name,a) values('g',5);
Query OK, 1 row affected (0.00 sec)

mysql> insert into test123(name,a) values('g',6);
Query OK, 1 row affected (0.01 sec)

mysql> insert into test123(name,a) values('g',7);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test123;
+-----+------+------+
| id  | name | a    |
+-----+------+------+
| 120 | g    |    1 |
| 121 | g    |    2 |
| 122 | g    |    3 |
| 123 | g    |    4 |
| 124 | g    |    5 |
| 125 | g    |    6 |
| 126 | g    |    7 |
+-----+------+------+
7 rows in set (0.00 sec)

mysql> insert into test123(name,a) values('g',1) on duplicate key update name='g';
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test123(name,a) values('g',1) on duplicate key update name='g';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test123(name,a) values('g',1) on duplicate key update name='g';
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test123(name,a) values('g',1) on duplicate key update name='g';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test123(name,a) values('g',1) on duplicate key update name='g';
Query OK, 0 rows affected (0.01 sec)

mysql> select * from test123;
+-----+------+------+
| id  | name | a    |
+-----+------+------+
| 120 | g    |    1 |
| 121 | g    |    2 |
| 122 | g    |    3 |
| 123 | g    |    4 |
| 124 | g    |    5 |
| 125 | g    |    6 |
| 126 | g    |    7 |
+-----+------+------+
7 rows in set (0.00 sec)

这里数据虽然没有变化但是自增最大值变了,再次插入一条数据如下,
mysql> insert into test123(name,a) values('g',8);
Query OK, 1 row affected (0.00 sec)

mysql> select *from test123;
+-----+------+------+
| id  | name | a    |
+-----+------+------+
| 120 | g    |    1 |
| 121 | g    |    2 |
| 122 | g    |    3 |
| 123 | g    |    4 |
| 124 | g    |    5 |
| 125 | g    |    6 |
| 126 | g    |    7 |  ->gap
| 132 | g    |    8 |  ->gap
+-----+------+------+
8 rows in set (0.00 sec)

可以看到 126和132之间的自增就丢失了。

MySQL:自增不连续的几种情况总结


原文始发于微信公众号(MySQL学习):MySQL:自增不连续的几种情况总结

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/288947.html

(0)
土豆大侠的头像土豆大侠

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!