MySQL中自增主键的作用是什么

  

本篇文章为大家展示了MySQL中自增主键的作用是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

特点

保存策略

1、如果存储引擎是 MyISAM,那么这个自增值是存储在数据文件中的;

2、如果是 InnoDB引擎,1)在 5.6之前是存储在内存中,没有持久化,在重启后会去找最大的键值,举个例子,如果一个表当前数据行里最大 id是10,AUTO_INCREMENT=11。这时候,我们删除 id=10 的行,AUTO_INCREMENT 还是 11。但如果马上重启实例,重启后这个表的 AUTO_INCREMENT 就会变成 10;

            2)在 8.0开始,自增值就保存在 redo log中,重启后会从 redo log中读取之前保存的自增值。

自增值的确定

1、如果插入数据时 id字段指定为0、null或未指定,那么就把这个表当前的 AUTO_INCREMENT值填到自增字段,并且会以auto_increment_offset作为初始值,auto_increment_increment为步长,找出第一个大于当前自增值的值作为新的自增值。

2、如果插入的数据的 id字段指定了具体的值,就直接使用语句里的值。

在一些场景下,使用的就不全是默认值。比如,双 M 的主备结构里要求双写的时候,我们就可能会设置成 auto_increment_increment=2,让一个库的自增 id 都是奇数,另一个库的自增 id 都是偶数,避免两个库生成的主键发生冲突。

自增值的修改

假设某次要输入的值是 X,当前的自增值是 Y。那么:

1、如果 X

2、如果X≥Y,那么就把当前自增值修改为新的自增值。

执行过程

假设有表t ,id是自增主键,在已有 (1,1,1)的情况下,插入一条 (null,1,1),那么执行过程就如下:

1、执行器调用 InnoDB 引擎接口写入一行,传入的这一行的值是 (0,1,1);

2、InnoDB 发现用户没有指定自增 id 的值,获取表 t 当前的自增值 2;

3、将传入的行的值改成 (2,1,1);

4、将表的自增值改成 3;

5、继续执行插入数据操作,由于已经存在 c=1 的记录,所以报 Duplicate key error,语句返回。

MySQL中自增主键的作用是什么

带来的问题

由于上面说得这种特性,在一些场景中会出现主键不连续的现象。

场景1:添加数据时唯一索引重复

MySQL中自增主键的作用是什么

在 c列索引重复后,原本要分配的主键值 2就会被丢弃,而下次再次插入就从 2 开始计算,也就变成了 3。

场景2:事务回滚

insert into t values(null,1,1);
  开始;
  insert  into  t 价值(零2 2);
  回滚;
  insert  into  t 价值(零2 2);//插入的行是(3 2 2)

在第二条语句回滚后分配给其的主键2也会被丢弃。

<>强场景3:特殊批插入优化导致

这里说得特殊的批插入指的是插入…选择、更换…选择和数据加载语句。为什么说这些语句可能会导致吗?这就要说到自增锁了。首先自增锁是为了避免多线程冲突,因为在多线程下,如果同时有多个线程来获取自增值,那么就可能会导致同一个自增值被分配给多条记录,导致逐渐冲突。所以需要自增锁,而为什么前面说得这些批插入语句会导致主键不连续,在下面自增锁部分会说到。

问题:在说自增锁之前,先思考一个问题,为什么对于前两个场景,不把自增主键值设为可以回滚的?这样不就可以避免不连续了么?

答:因为设计成可回滚的会导致性能下降,看下面这个场景。

1,假设事务一个申请到了id=2,事务B申请到id=3,那么这时候表t的自增值是4,之后继续执行。

2,事务B正确提交了,但事务一出现了唯一键冲突。

3,如果允许事务一把自增id回退,也就是把表t的当前自增值改回2,那么就会出现这样的情况:表里面已经有id=3的行,而当前的自增id值是2 .

4,接下来,继续执行的其他事务就会申请到id=2,然后再申请到id=3。这时,就会出现插入语句报错”主键冲突”。

而为了解决上面这个问题,就需要从下面两个方法中选一个。

方法一,每次申请id之前,先判断表里面是否已经存在这个id。如果存在,就跳过这个id。但是,这个方法的成本很高。因为,本来申请id是一个很快的操作,现在还要再去主键索引树上判断id是否存在。

MySQL中自增主键的作用是什么