自增主键为什么不是连续的
自增值的存储
表的自增值是保存在表结构定义里,表的结构定义放在后缀名为.frm的文件中,但是并不会保存自增值。
不同的引擎对于自增值的保存策略不同。
- MyISAM引擎保存在数据文件中。
- InnoDB引擎自增值,其实保存在了内存里。5.7版本以前会去寻找最大的max(id),放入内存中。而5.8以后则是记录在了redo log中。
自增值修改机制
- 如果插入数据时id字段指定为0、null或者未指定值、把就这个表当前的AUTO_INCREMENT值填到自增字段;
- 如果插入数据id字段指定了具体的值,就直接使用语句里指定的值。
假设,某次要插入的值是X,当前的自增值是Y。
如果X<Y,那么这个表的自增值不变;
如果X≥Y,需要把当前自增值修改为新的自增值。
新的自增值生成算法是:从auto_increment_offset 开始,以auto_increment_increment为步长,直到着到第一个大于X的值,作为新的自增值。
自增值的修改时机
自增数据的是在真正执行插入数据的操作之前。
自增主键id不连续的原因
1.唯一键冲突
2.事务的回滚
3.批量插入
InnoDB语句执行失败也不回退自增id。所以才只保证了自增id是递增的,但不保证是连续的。
自增锁优化
自增锁id并不是一个事务锁,而是每次申请完就马上释放。
对于批量插入数据的语句,MySQL有一个批量申请自增id的策略
1.语句执行过程中,第一次申请自增id,会分配1个;
2.1个用完以后,这个语句第二次申请自增id,会分配2个;
3.2个用完以后,这个语句第三次申请自增id,会分配4个;
4.依次类推,同一个语句去申请自增id,每次申请到的自增id个数都是上一次的两倍。
在生产上,尤其是有insert…select这种批量插入数据的场景时,从并发插入数据的角度考虑,建议设置
innodb_autoinc_lock_mode=2 ,并且 binlog_format=row.