MySQL的innodb表批量插入数据时,自增主键不连续原因和解决办法

问题说明

在mysql中造测试数据时,出现了主键不连续的情况

CREATE TABLE test  ( 
	id int NOT NULL AUTO_INCREMENT COMMENT 'ID', 
	name varchar(255) , 
	PRIMARY KEY (id) 
);

insert into test (name) VALUES ('A');

insert into test (name) select name from test; 
insert into test (name) select name from test; 
insert into test (name) select name from test; 
insert into test (name) select name from test;

select * from test;

结果:

`1  A`
`2  A`
`3  A`
`4  A`
`6  A`
`7  A`
`8  A`
`9  A`
`13 A`
`14 A`
`15 A`
`16 A`
`17 A`
`18 A`
`19 A`
`20 A`

5,10,11,12 丢失了

原因分析

经查询发现是innodb存储引擎有三种自增模式

innodb_autoinc_lock_mode 变量有三种可能的设置:0、1 或 2,分别对应“传统”(traditional)、“连续”(consecutive)和“交错”(interleaved)锁模式。在 MySQL 8.4 中,默认设置为交错锁模式(innodb_autoinc_lock_mode=2)。

SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode';
Variable_nameValue
innodb_autoinc_lock_mode2

交错锁模式是默认设置。

  • innodb_autoinc_lock_mode = 0(“传统”锁模式)

在此锁定模式下,所有类型的insert语句都会获得一个特殊的表级AUTO-INC锁,用于插入具有AUTO_INCREMENT列的表。即每当执行insert的时候,都会得到一个表级锁(AUTO-INC锁),使得语句中生成的auto_increment为顺序,且在binlog中重放的时候,可以保证master与slave中数据的auto_increment是相同的。因为是表级锁,当在同一时间多个事务中执行insert的时候,对于AUTO-INC锁的争夺会限制并发能力。

  • innodb_autoinc_lock_mode = 1(“连续”锁模式)

在MySQL8.0之前,连续锁定模式是默认的。在这个模式下,“bulkinserts”仍然使用AUTO-INC表级锁,并保持到语句结束。这适用于所有INSERT…SELECT,REPLACE…SELECT和LOADDATA语句。同一时刻只有一个语句可以持有AUTO-INC锁。对于“Simpleinserts”(要插入的行数事先已知),则通过在mutex(轻量锁)的控制下获得所需数量的自动递增值来避免表级AUTO-INC锁,它只在分配过程的持续时间内保持,而不是直到语句完成。不使用表级AUTO-INC锁,除非AUTO-INC锁由另一个事务保持。如果另一个事务保持AUTO-INC锁,则“Simpleinserts”等待AUTO-INC锁,如同它是一个“bulkinserts”。在一个时间点,只能有一个语句持有 AUTO-INC 锁并执行。如果批量插入操作的源表和目标表不同,目标表上的 AUTO-INC 锁会在对源表的第一行加共享锁后获取。如果源表和目标表相同,AUTO-INC 锁会在对所有选定行加共享锁后获取。此锁模式确保,即使执行了插入语句,其中的自动增长值也是连续的,并且对于基于语句的复制是安全的。

  • innodb_autoinc_lock_mode = 2(“交错”锁模式)

从MySQL8.0开始,交错锁模式是默认设置。在此锁定模式下,自动递增值保证在所有并发执行的所有类型的insert语句中是唯一且单调递增的。但是,由于多个语句可以同时生成数字(即,跨语句交叉编号),为任何给定语句插入的行生成的值可能不是连续的。

解决办法

在配置文件如my.inimy.cnf中增加一行

innodb_autoinc_lock_mode=0

切换到连续模式,在并发场景性能相对较差,主键的不连续通常不影响业务,无特殊需求不建议修改

参考

[1] http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference
[2] https://dev.mysql.com/doc/refman/8.4/en/innodb-auto-increment-handling.html#innodb-auto-increment-lock-modes
[3] https://stackoverflow.com/questions/14641847/how-to-change-innodb-autoinc-lock-mode-to-be-set-to-0-from-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值