美文网首页sql个人学习
MySQL性能(4)—AUTO_INCRMENT锁机制(inno

MySQL性能(4)—AUTO_INCRMENT锁机制(inno

作者: 小胖学编程 | 来源:发表于2020-03-03 21:18 被阅读0次

在mysql的InooDB存储引擎中,常用的是自增(AUTO_INCRMENT)主键,因为InnoDB是聚簇索引。

使用自增主键可以保证数据行是按顺序写入的。若是使用无序的聚簇索引,例如UUID,不仅索引占用的空间更大,而且也会导致页分裂和碎片化现象。

引用自—高性能mysql第三版.png

使用自增索引,在高并发的情况下可能存在性能问题,一个就是间隙锁影响性能,而另一个就是AUTO_INCREMENT锁机制会影响性能。

1. InnoDB中AUTO_INCREMENT处理

若是在InnoDB中使用AUTO_INCREMENT机制,那么自增列必须是索引的一部分,以便可以等效于对表进行索引查找以获取最大列值。

innodb_autoinc_lock_mode配置可以控制在向auto_increment列表插入数据时相关锁的行为以及主从数据一致性的平衡。

1.1 插入(INSERT LIKE)的分类

1.1.1. Simple inserts(简单插入)

是可以预先确定将要插入行数的insert语句,包括单行和多行INSERT语句,例如INSERT, INSERT … VALUES(),VALUES()语法。

1.1.2. Bulk inserts(大量插入)

事先不知道要插入的行数的语句,包括INSERT ... SELECTREPLACE ... SELECTLOAD DATA语句,但不是纯INSERT,每处理一行时,一次为一列分配新增的AUTO_INCRMENT

1.1.3. Mixed inserts(混合模式插入)

  • 一些特殊的“简单插入”语句,用于指定部分(但不是全部)新行的自动增量值,例如INSERT INTO t1 (c1,c2) VALUES (1,'a'), (NULL,'b'), (5,'c'), (NULL,'d');
  • 例如INSERT … ON DUPLICATE KEY UPDATE,在最坏的情况下实际上是INSERT紧跟着UPDATE,其中AUTO_INCREMENT在更新阶段可能会或者不会使用为列分配的值。

1.2 innodb_autoinc_lock_mode配置

1.2.1. 版本更新:

  • 在mysql5.1.22版本之前,是不支持innodb_autoinc_lock_mode配置的。
  • 在mysql8.0之前,默认innodb_autoinc_lock_mode=1,即连续锁定模式。
  • 在mysql8.0开始,默认innodb_autoinc_lock_mode=2,即交错锁定模式。

因为Mysql8.0之前,备份(binlog)默认是基于语句(statement模式)的复制。而Mysql8.0开始,binlog默认是基于行(row模式)的复制。

基于语句的复制需要连续的自动增量锁定模式,以确保为给定的SQL语句序列以可预测和可重复的顺序分配自动增长值。而基于行的复制对SQL语句的执行顺序不敏感。

1.2.2. 配置详情

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

该模式是Mysql5.1之前未引入innodb_autoinc_lock_mode配置参数时的行为,提供了传统的锁定模式选项以实现向后兼容。

在这种模式下,所有INSERT语句(INSERT LIKE)都会获得特殊的表级AUTO-INC锁定,将其插入具有AUTO_INCREMENT列的表中。此锁定通常保持在语句的末尾(而不是事务的末尾)。

举例分析:假设有两个事务正在运行,每个事务都将行插入具有AUTO_INCREMENT列的表中。一个事务使用insert ... select插入1000行的语句,另一事务使用insert插入一个行的简单语句:

Tx1: INSERT INTO t1 (c2) SELECT 1000 rows from another table ...
Tx2: INSERT INTO t1 (c2) VALUES ('xxx');

InooDB无法预先判断Tx1会插入多少行,Tx1使用表级锁(保持在该语句的末尾)去阻塞Tx2的并发执行,Tx1每次插入时均分配一个自增id,最终t1语句生成的递增主键是连续的。在主从复制或者故障恢复时,若binlog使用statement模式(基于语句的复制),主从服务器执行insert语句得到的结果是完全相同的。

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

Mysql5.1.2-Mysql8.0innodb_autoinc_lock_mode的默认配置。

  • simple inserts:直接通过分析语句,获取要插入的的数量,然后一次性分配足够的auto_increment id,只会将整个分配过程锁住。
  • Bulk inserts:[[bʌlk]]因为不能确定插入的数量,因此还会将表锁住;
  • Mixed-mode inserts:直接分析语句,获取最坏情况下需要插入的数量,然后一次性分配足够的auto increment id,只会将整个分配过程锁住。

innodb_autoinc_lock_mode = 2 (“交叉”锁定模式)

这种模式下插入语句(INSERT LIKE)来一个分配一个,而不会锁表,只会锁住分配ID的过程,和innodb_autoinc_lock_mode = 1区别bulk insert是不会预分配多个,这种方式的并发性最高。

若是binlog的模式为statement模式,由于并发情况下Bulk inserts在分配的时会同时向其他insert分配,会出现主从不一致的情况。

所以需要配合binlogrow模式使用。

2. InnoDB的自增主键特性

  1. 主从复制下锁定策略

如果binlog为statement模式(基于语句的复制),请将innodb_autoinc_lock_mode设置为0或1,并在主设备及从设备上使用相同的值。
如果binlog是row模式或者mixed模式,则innodb_autoinc_lock_mode均是安全的。因为基于行的复制对于SQL语句的执行顺序不敏感。

  1. “丢失”自增值和序列间隙

在所有锁定模式(0,1和2)中,如果生成自增值的事务回滚,则这些自增值将“丢失”。为自动递增列生成值后,无论“INSERT like”语句是否完成,以及包含的事务是否回滚,都无法回滚该值。这样丢失的值不会被重用。因此,自增列中的值有间隙。

  1. 自增列上的NULL和0

在所有锁模式(0,1和2)中,如果用户未INSERT中的AUTO_INCREMENT列指定NULL或0,InnoDB会将该行视为未指定值并为其生成新值。

  1. 为自动递增列指定负值

在所有锁定模式(0,1和2)中,如果为“auto_increment”列指定负值,则自增特性不会生效(持久化的为负值)。

  1. “大量插入(bulk inserts)”下自增列与间隙

当innodb_autoinc_lockm_mode设置为0或1时,任何给定语句生成的自增值都是连续的,没有间隙。因为会使用表锁一直到语句结束,并且一次只能执行一个这样的语句。

在innodb_autoinc_lockm_mode=2的情况下,在“bulk inserts”并发执行时,生成的自增列可能存在间隙。

6. 更新自增列的值

第一步:插入数据(0和null会执行自增策略)

create table t(x int auto_increment not null primary key);
insert into t(x) values(0),(null),(3);
select * from t;
+---+
| x |
+---+
| 1 |
| 2 |
| 3 |
+---+

第二步:修改sql中的自增列。

update t set x=4 where x=1;
select * from t;
+---+
| x |
+---+
| 2 |
| 3 |
| 4 |
+---+

第三步:再次插入

insert into t(x) values(0);
ERROR 1062 (23000): Duplicate entry '4' for key 'PRIMARY'

第四步:分析

执行完第一步后,mysql的自增序列生成器知道下一个自增值为4;

执行第二步,mysql并不知道自增列4已经被人占用,所以执行第三步的时候就出现异常。

官方文档

官方文档—InnoDB中的AUTO_INCREMENT处理

相关文章

  • MySQL性能(4)—AUTO_INCRMENT锁机制(inno

    在mysql的InooDB存储引擎中,常用的是自增(AUTO_INCRMENT)主键,因为InnoDB是聚簇索引。...

  • Innodb的锁

    Innodb的锁是行级锁 mysql delete是否会锁表 MySQL的InnoDB存储引擎支持行级锁,Inno...

  • 系统运维告警阈值

    数据库连接数:大于1600,触发警告运行线程数:大于25,触发警告锁:MySQL InnoDB 行锁过多,inno...

  • 4 mysql锁机制

    4.1 概述 4.1.1 定义 4.1.2 生活购物 4.1.3 锁的分类 从数据操作的类型(读、写)分 读锁(共...

  • MySQL的锁机制

    MySQL锁简介 MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。比如,MyISAM和...

  • MySQL的锁机制

    mysql的锁机制 1、MySQL锁的基本介绍 MyISAM:MySQL的表级锁有两种模式:表共享读锁(Table...

  • 7)InnoDB加锁案例分析

    前面分析过MySQL的锁分类方式,MyISAM仅支持表锁,不支持行锁,所以不需要做过多分析。这篇文章就针对Inno...

  • MySQL性能优化(九)-- 锁机制之行锁

    一、行锁概念及特点 1.概念:给单独的一行记录加锁,主要应用于innodb表存储引擎 2.特点:在innodb存储...

  • 共享 + 排他锁

    mysql锁机制分为表级锁和行级锁 ,mysql中行级锁中的共享锁与排他锁进行分享交流。 测试语法 begin; ...

  • 13.MySQL锁机制

    MySQL锁 相对于其他的数据库而言,MySQL的锁机制比较简单,最显著的特点就是不同的存储引擎支持不同的锁机制。...

网友评论

    本文标题:MySQL性能(4)—AUTO_INCRMENT锁机制(inno

    本文链接:https://www.haomeiwen.com/subject/xkmhlhtx.html