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 ...
随机推荐
- 安装和使用nltk
安装 参考:https://www.cnblogs.com/zrmw/p/10869325.html 分词:注意先分句再分词,这些对象均来自nltk.tokenize库 word_tokenize 导 ...
- SQL经典实例笔记
目录 前言 第一章:检索记录 在Where字句中使用别名 前言 本文是根据我阅读的书籍SQL经典实例而写的笔记,只记载我觉得有价值的内容 第一章:检索记录 在Where字句中使用别名 --错误实例 s ...
- All LeetCode Questions List 题目汇总
All LeetCode Questions List(Part of Answers, still updating) 题目汇总及部分答案(持续更新中) Leetcode problems clas ...
- linux 把nginx加入到系统服务的方法
linux 把nginx加入到系统服务的方法一.首先写一个shell脚本,脚本名称:nginx<pre>#! /bin/bash# chkconfig: 35 85 15 # descri ...
- RocketMQ 4.5.1 双主双从异步复制环境搭建
基础环境 操作系统:CentOS7 实例:192.168.63.129,192.168.63.130,192.168.63.131,192.168.63.132 Java:jdk-8u191-linu ...
- SQL Server 中的Merge关键字(转载)
简介 Merge关键字是一个神奇的DML关键字.它在SQL Server 2008被引入,它能将Insert,Update,Delete简单的并为一句.MSDN对于Merge的解释非常的短小精悍:”根 ...
- [Docker] Windows 宿主环境下,共享或上传文件到容器的方法
需求如题. 解决方案1 - 挂载目录(适用于创建新的容器) 格式-v 容器目录 或 -v 本地目录:容器目录 范例Linux宿主环境下:使用镜像 nginx:latest,以后台模式启动一个容器,将容 ...
- python 通过Sybase ASE ODBC Driver访问sybase数据库,无需配置DSN【自己整理的】
Python语言对于开发工程师或者测试工程师来说,应该是最高效的开发语言之一.但python访问sybase数据库的资料相对少见.而且sybase字符集为GB1803时,python访问sybase库 ...
- sizeof运算符和strlen()函数
首先放上代码和运行结果.(在VC6.0上运行) #include<stdio.h> #include<string.h> int main(void) { char s1[]= ...
- golang使用json格式实现增删查改
需求和思路 在一般的小项目或者一个小软件,例如客户端之类的小程序中,可能会需要数据的持久化.但是使用一般的数据库(Mysql)之类的不合适.使用sqlite3这种嵌入式的是个较好的方法,但是Go语言中 ...