MySQL AutoIncrement--自增锁模式
自增锁模式
在MYSQL 5.1.22版本前,自增列使用AUTO_INC Locking方式来实现,即采用一种特殊的表锁机制来保证并发插入下自增操作依然是串行操作,为提高插入效率,该锁会在插入语句完成后立即释放,而不是插入语句所在事务提交时释放。该设计并发性能太差,尤其在大批量数据在一条语句中插入时(INSERT SELECT ), 会导致该语句长时间持有这个“表锁”,从而阻塞其他事务的插入操作。
在MYSQL 5.1.22版本开始,InnoDB存储引使用一种轻量级互斥锁(Mutex)来控制自增列增长,并提供innodb_autoinc_lock_mode参数来控制。
自增长方式可分为下面四类:
.INSERT-LIKE:指所有的插入语句,比如 INSERT、REPLACE、INSERT…SELECT、REPLACE…SELECT,LOAD DATA等。
.Simple insert:指在插入前就能确定插入行数的语句,包括INSERT、REPLACE,不包含INSERT…ON DUPLICATE KEY UPDATE这类语句。
.Bulk inserts:指在插入前不能确定得到插入行的语句。如INSERT…SELECT,REPLACE…SELECT,LOAD DATA.
.Mixed-mode inserts:指其中一部分是子增长的,有一部分是确定的。
innodb_autoinc_lock_mode参数取值
.innodb_autoinc_lock_mode=0 传统锁定模式, 5.1.22之前的方式,也就是所有INSERT-LIKE操作都用AUTO-inc locking。
.innodb_autoinc_lock_mode= 连续锁定模式,这个参数是5..22之后出现的也是之后的默认值,对于SIMPLE INSERT,使用轻量级互斥锁,对于BULK INSERT,使用AUTO-inc locking。
.innodb_autoinc_lock_mode= 交错锁定模式,指不管什么情况都使用轻量级互斥的锁,效率最高,但是复制只能使用row-basereplication,因为statement-base replication会出现问题。
当innodb_autoinc_lock_mode=1时,"Simple insert"操作能在插入前知道插入的记录数量,因此无需在整个插入操作过程中持有表级别的AUTO-INC锁,MySQL通过轻量级互斥锁来控制INSERT操作获取自增值的过程,并在INSERT操作获取到自增值后快速释放互斥锁,通过降低锁颗粒度和锁持续周期,实现"Simple insert"操作并发执行。当其他事物对表持有AUTO-INC锁时,"Simple insert"操作也会升级使用AUTO-INC锁并被阻塞。
当innodb_autoinc_lock_mode=1时,在语句复制格式下(BINLOG_FORMAT=STATEMENT),BINLOG中没有记录主库执行过程中获取到的所有自增值及其对应行的信息,要保证"Bulk insert"操作主从复制数据一致就必须保证语句在主库和从库执行时获取到相同自增值,而因此只能通过控制“获取连续自增值”的方式来实现,同时为避免受其他事务插入操作影响,就必须在表级别加锁且保证持有锁至语句结束。
在行复制格式下(BINLOG_FORMAT=ROW),主库BINLOG中保存有记录的所有列信息包括自增列值,因此无需通过AUTO-INC锁来保证主从数据一致。
在MySQL 8.0版本前,参数BINLOG_FORMAT的默认值为STATEMENT,参数innodb_autoinc_lock_mode的默认值为1。
在MySQL 8.0版本后,参数BINLOG_FORMAT的默认值被调整为ROW格式,参数innodb_autoinc_lock_mode的默认值为2。
自增值间隙
在MySQL中,获取自增值的操作是非事务性,获取自增值的操作产生的锁在语句执行过程中或执行完成里便被释放而不会持续到事务提交和回滚,获取到自增值也不会随事务回滚而回滚,因此不能依赖MySQL自增列来实现表中列值连续无间隙。
表中自增列作为代理键,只能用来标识和定位记录,而不应该承载业务逻辑,因此也不建议对自增列值进行显式更新。
AUTO_INC锁导致的死锁
在业务繁忙的表上通过pt-osc进行DDL操作变更时,可能会出现死锁,死锁场景如下:
pt-osc工具执行对tb001执行DDL变更操作,创建临时表_tb001_new来执行变更并拷贝数据,并在tb001上创建增删改三种触发器。 步骤1、事务1执行业务操作对表tb001进行数据更新,对更新记录加排他锁(X) 步骤2、pt-osc的拷贝线程拷贝数据,事务2执行INSERT INTO _tb001_new SELECT FROM tb001 WHERE ... LOCK IN SHARE MODE的操作,先执行INSERT INTO操作申请_tb001_new表上AUTO-INC锁,申请成功 步骤3、事务1更新操作触发表tb0011上update触发器执行中执行REPLACE INTO操作,向表_tb001_new更新插入数据,申请_tb001_new表上AUTO-INC锁,由于事务2持有_tb001_new表上AUTO-INC锁,因此事务1被阻塞。 步骤4、事务2获取_tb001_new表上AUTO-INC锁后,再执行SELECT FROM tb001 WHERE ... LOCK IN SHARE MODE操作,申请某个范围内所有记录上的共享锁(S),由于事务1持有其中一条或多条记录的排他锁(X),导致事务2被阻塞。 步骤5、事务2被阻塞,触发死锁检测,发现事务1和事务2相互等待锁资源形成死锁,挑选事务1或事务2进行事务回滚。
上述死锁解决办法:
1、在行复制格式下(BINLOG_FORMAT=ROW),可以考虑调整参数innodb_autoinc_lock_mode的值为2(非动态参数,需重启服务)
2、通过降低锁冲突概率来降低死锁发生概率:
、在业务低峰期进行DDL变更操作
、优化业务SQL降低单个事务修改记录数
、调整pt-osc单次拷贝操作的数据量
参考资料:
https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_autoinc_lock_mode
MySQL AutoIncrement--自增锁模式的更多相关文章
- MySQL自增锁模式innodb_autoinc_lock_mode参数理解调优
前段时间某数据表运行过程中,出现自增字段突然跳跃式增长的问题,潜心研究发现,问题导致原因可能是因为并发写入导致 于是通过各种途径查阅是因为innodb_autoinc_lock_mode参数设置的不同 ...
- 深入剖析 MySQL 自增锁
之前的文章把 InnoDB 中的所有的锁都介绍了一下,包括意向锁.记录锁...自增锁巴拉巴拉的.但是后面我自己回过头去看的时候发现,对自增锁的介绍居然才短短的一段. 其实自增锁(AUTO-INC Lo ...
- Mysql研磨之InnoDB行锁模式
事务并发带来的一些问题 (1)更新丢失(LostUpdate):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题最后的更新覆盖了由其 ...
- mysql 开发进阶篇系列 7 锁问题(innodb锁争用情况及锁模式)
1 .获取innodb行锁争用情况 1.1 通过检查innodb_row_lock状态变量来分析系统上的行锁的争夺情况 SHOW STATUS LIKE 'innodb_row_lock%' 通过in ...
- MySQL自增锁等待问题解决
有网友再群里问:在做基准测试时候,批量插入数据时,有很多自增锁等待,我告诉他解决办法: 1.innodb_autoinc_lock_mode=2 2.innodb_autoextend_increme ...
- INNODB自增主键的一些问题 vs mysql获得自增字段下一个值
今天发现 批量插入下,自增主键不连续了....... InnoDB AUTO_INCREMENT Lock Modes This section describes the behavior of A ...
- 【MySQL】索引和锁
前言 本文摘自数据库两大神器[索引和锁] 声明:如果没有说明具体的数据库和存储引擎,默认指的是MySQL中的InnoDB存储引擎 索引 在之前,我对索引有以下的认知: 索引可以加快数据库的检索速度 表 ...
- MySql InnoDB中的锁研究
# MySql InnoDB中的锁研究 ## 1.InnoDB中有哪些锁### 1. 共享和排他(独占)锁(Shared and Exclusive Locks) InnoDB实现标准的行级锁定,其中 ...
- MySQL的死锁系列- 锁的类型以及加锁原理
疫情期间在家工作时,同事使用了 insert into on duplicate key update 语句进行插入去重,但是在测试过程中发现了死锁现象: ERROR 1213 (40001): De ...
随机推荐
- bootcss 之 .table-hover 类 鼠标悬停
通过添加 .table-hover 类可以让 <tbody> 中的每一行对鼠标悬停状态作出响应. <table class="table table-hover" ...
- k8s记录-Dockerfile详解
Dockerfile命令详解 下面我们来分别介绍下上面使用到的命令: FROM 格式:FROM 或FROM :. 解释:FROM必须是Dockerfile里的第一条指令(注视除外),后面跟有效的镜像名 ...
- LwIP应用开发笔记之四:LwIP无操作系统TFTP服务器
前面我们已经实现了UDP的回环客户端和回环服务器的简单应用,接下来我们实现一个基于UDP的简单文件传输协议TFTP. 1.TFTP协议简介 TFTP是TCP/IP协议族中的一个用来在客户机与服务器之间 ...
- 构建一个java环境的centos系统镜像并上传到阿里云镜像仓库
编辑dockerfile 文件 FROM centos MAINTAINER zhaoweifeng ENV LANG en_US.UTF-8 RUN /bin/cp /usr/share/zonei ...
- Vue父子组件相互传值及调用方法的方案
Vue父子组件相互传值及调用方法的方案 一.调用方法: 1.父组件调用子组件方法: 2.子组件调用父组件方法: 参考:https://www.cnblogs.com/jin-zhe/p/9523782 ...
- [数据结构 - 第3章] 线性表之顺序表(C++实现)
一.类定义 顺序表类的定义如下: #ifndef SEQLIST_H #define SEQLIST_H typedef int ElemType; /* "ElemType类型根据实际情况 ...
- Kubernetes k8s 基于Docker For Windows
开启和安装Kubernetes k8s 基于Docker For Windows 0.最近发现,Docker For Windows Stable在Enable Kubernetes这个问题上 ...
- css3网站响应式写法
css3响应式写法因为media不支持ie9以下的浏览器 所有要加个判断<pre> <!-- 全部通用的 --><link rel="stylesheet&qu ...
- Linux字符设备驱动基本结构
1.Linux字符设备驱动的基本结构 Linux系统下具有三种设备,分别是字符设备.块设备和网络设备,Linux下的字符设备是指只能一个字节一个字节读写的设备,不能随机读取设备内存中某一数据,读取数据 ...
- Mysql 查询时间段是否可用,查询时间段是否有交集
最近遇到 类似, 会议室预订的模型, 基本上 是 会议室 + 时间段来检测是否被占用. 其实思路比较简单 , 一开始的思路是 去查询 自己选择的时间段 与数据库已经存在的时间段匹配 是否 可用, ...