锁表:MyISAM非聚集索引和InnoDB聚集索引的各种锁表问题
参考文献
Mysql数据库中的各种锁_张花生的博客-CSDN博客_数据库锁
面试官:MySQL死锁有哪些场景?如何避免?
概述
相对其他数据库而言,MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制。
一.导致锁表的原因
锁表发生在insert,update,delete中
锁表的原理是数据库使用独占式封锁机制,当执行上面的语句时,对表进行锁住,直到发生commite或者回滚或者退出数据库用户
锁表的原因:
第一.A程序执行了对tableA的insert,并还未commite时,B程序也对tableA进行insert,则此时会发生资源正忙的异常,也就是锁表
第二.锁表常发生于并发而不是并行(并行时,一个线程操作数据库时,另一个线程是不能操作数据库的,cpu和io分配原则)
减少锁表的概率:
减少insert,update,delete语句执行到commite之间的时间.具体点:批量执行改为单个执行,优化sql自身的非执行速度
如果异常,对事务进行回滚
MySQL大致可归纳为以下3种锁:
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
MyIsam锁表:不支持事务,不会出现死锁
在使用MyIsam时,我们只可以使用表级锁,而MySQL的表级锁有两种模式:
表共享锁(Table Read Lock)和表独占写锁(Table Write Lock),他们在工作时表现如下:
对某一个表的读操作,不会阻塞其他用户对同一表请求,但会阻塞对同一表的写请求;
对MyISAM的写操作,则会阻塞其他用户对同一表的读和写操作;
MyISAM表的读操作和写操作之间,以及写操作之间是串行的。
InnoDB锁表:支持事务,会出现死锁
InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION);二是采用了行级锁。
行级锁和表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题。
InnoDB实现了以下两种类型的行锁。
共享锁(s):允许一个事务去读一行,阻止其他事务获得相同数据集的排他锁。xxx lock in share mode
排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务取得相同的数据集共享读锁和排他写锁。xxx for update
另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表锁。
意向共享锁(IS):事务打算给数据行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
间隙锁(Next-Key锁)
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB(可重复读、串行化级别下才有效)会给符合条件的已有数据的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(Next-Key锁)。
举例来说,假如emp表中只有101条记录,其empid的值分别是1,2,...,100,101,下面的SQL:
SELECT * FROM emp WHERE empid > 100 FOR UPDATE
是一个范围条件的检索,InnoDB不仅会对符合条件的empid值为101的记录加锁,也会对empid大于101(这些记录并不存在)的“间隙”加锁。
InnoDB使用间隙锁的目的
一方面是为了防止幻读,以满足相关隔离级别的要求,对于上面的例子,要是不使用间隙锁,如果其他事务插入了empid大于100的任何记录,那么本事务如果再次执行上述语句,就会发生幻读
另一方面,是为了满足其恢复和复制的需要。有关其恢复和复制对机制的影响,以及不同隔离级别下InnoDB使用间隙锁的情况
很显然,在使用范围条件检索并锁定记录时,InnoDB这种加锁机制会阻塞符合条件范围内键值的并发插入,这往往会造成严重的锁等待因此,在实际开发中,尤其是并发插入比较多的应用,我们要尽量优化业务逻辑,尽量使用相等条件来访问更新数据,避免使用范围条件。
其次,间隙锁的存在可能会导致死锁,如下:
注意:不同session下的间隙锁之间不会冲突(间隙锁不互锁),跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作
二.用索引字段做为条件进行修改时, 是否表锁的取决于这个索引字段能否确定记录唯一,当索引值对应记录不唯一,会进行锁表,相反则行锁
例:
存储过程循环30次更新操作(cycore_file_id 为唯一标识)
执行结果:持续一段时间后速度越来越慢,出现等待锁
原因
MySQL的innodb存储引擎支持行级锁,innodb的行锁是通过给索引项加锁实现的,这就意味着只有通过索引条件检索数据时,innodb才使用行锁,否则使用表锁。根据当前的数据更新语句(update jx_attach set complete=1,attach_size=63100 where cycore_file_id=‘hahaha’;),该条件字段cycore_file_id并没有添加索引,所以导致数据表被锁。
解决办法 为cycore_file_id添加索引
假设kid是表table 的 一个索引字段 且值不唯一
如果kid 有多个值为12的记录那么: update table set name=’feie’ where kid=12; 会锁表
如果kid有唯一的值为1的记录那么: update table set name=’feie’ where kid=1; 不会锁
三.同一个表,如果进行删除操作时,尽量让删除条件统一,否则会相互影响造成锁表
例:
如果有两个delete 而 kid1 与 kid2是索引字段
语句1 delete from table where kid1=1 and kid2=2; 语句2 delete from table where kid1=1 and kid2=3; 这样的两个delete 是不会锁表的
语句1 delete from table where kid1=1 and kid2=2; 语句2 delete from table where kid1=1 ; 这样的两个delete 会锁表
什么时候使用表锁
对于InnoDB表,在绝大部分情况下都应该使用行级锁,因为事务和行锁往往是我们之所以选择InnoDB表的理由。但在个别特殊事务中,也可以考虑使用表级锁。
第一种情况是:事务需要更新大部分或全部数据,表又比较大,如果使用默认的行锁,不仅这个事务执行效率低,而且可能造成其他事务长时间锁等待和锁冲突,这种情况下可以考虑使用表锁来提高该事务的执行速度。
第二种情况是:事务涉及多个表,比较复杂,很可能引起死锁,造成大量事务回滚。这种情况也可以考虑一次性锁定事务涉及的表,从而避免死锁、减少数据库因事务回滚带来的开销。
关于死锁
MyISAM表锁是deadlock free的,这是因为MyISAM总是一次性获得所需的全部锁,要么全部满足,要么等待,因此不会出现死锁。但是在InnoDB中,除单个SQL组成的事务外,锁是逐步获得的,这就决定了InnoDB发生死锁是可能的。
发生死锁后,InnoDB一般都能自动检测到,并使一个事务释放锁并退回,另一个事务获得锁,继续完成事务。有以下两种处理方式
直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout来设置(默认50s),对于在线服务来说,这个等待时间往往是无法接受的
如果设置成1s,这样当出现死锁的时候,确实很快就可以解开,但如果不是死锁,而是简单的锁等待,则会造成很多误伤
(推荐)主动死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数innodb_deadlock_detect设置为on,表示开启这个逻辑
如果出现很多事务都要更新同一行的场景(热点行),每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁,这是一个时间复杂度是O(n)的操作。假设有1000个并发线程要同时更新同一行,那么死锁检测操作就是100万这个量级的。虽然最终检测的结果是没有死锁,但是这期间要消耗大量的CPU资源。因此,你就会看到CPU利用率很高,但是每秒却执行不了几个事务
对于上述的情况,如果能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉(头痛医头)
控制并发度,如过同一行同时最多只有10个线程在更新,那么死锁检测的成本很低,就不会CPU占用高的问题。这个并发控制最好是在数据库Server端 / 中间件进行,而不能在客户端,因为通常会有很多客户端/很多连接/很多线程。其思路一般是:对于相同行的更新,在进入引擎之前排队。这样在InnoDB内部就不会有大量的死锁检测工作了(不能让他进入数据库)
将一行改成逻辑上的多行来减少锁冲突
但在涉及外部锁,或涉及锁的情况下,InnoDB并不能完全自动检测到死锁,这需要通过设置锁等待超时参数innodb_lock_wait_timeout来解决。需要说明的是,这个参数并不是只用来解决死锁问题,在并发访问比较高的情况下,如果大量事务因无法立即获取所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖垮数据库。我们通过设置合适的锁等待超时阈值,可以避免这种情况发生
锁表:MyISAM非聚集索引和InnoDB聚集索引的各种锁表问题相关推荐
- mysql myisam表加索引_MyISAM和InnoDB的索引实现
在 MySQL 中,主要有四种类型的索引,分别为: B-Tree 索引, Hash 索引, Fulltext 索引和 R-Tree 索引.我们主要分析B-Tree 索引. B-Tree 索引是 MyS ...
- B+树在MySQL索引的应用和InnoDB的索引优化
B树索引算法介绍 1.B树 B树又称为多路平衡查找树,它类似普通的平衡二叉树,不同的一点是B树允许每个节点有更多的子节点. B树有如下特点: 具有n个关键字的节点含有(n+1)棵子树 所有键值分布在整 ...
- mysql索引数据结构图解_MySQL索引底层结构与实现原理
为什么要使用索引 MySQL官方定义为:索引(Index)是帮助 MySQL 高效获取数据的数据结构,类似于书的目录结构一样. 如果向mysql发出一条sql语句请求,查询的字段没有创建索引的话,可能 ...
- MySQL索引底层实现原理 MyISAM非聚簇索引 vs. InnoDB聚簇索引
MySQL索引底层实现原理 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. 我们知道,数据库查询是数据库的 ...
- 【MySQL索引】底层实现原理 MyISAM非聚簇索引 vs. InnoDB聚簇索引
MySQL索引底层实现原理 MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构. 我们知道,数据库查询是数据库的 ...
- 德鲁伊 oltp oltp_深入研究内存中OLTP表的非聚集索引
德鲁伊 oltp oltp With the introduction of Microsoft's new In-Memory OLTP engine* (code name Hekaton) a ...
- mysql的表是聚集索引组织表_Mysql的Innodb引擎索引总结
索引的目的是什么? 答:数据库添加索引的目的是为了加快查询速度. 索引的的数据结构是什么? 答:(这里的B是balance)B+树来存储索引,B+树类似于二叉树. B+树是怎么查找数据的? 答:B+树 ...
- MyISAM与InnoDB的索引实现
1.MyISAM 使用B+Tree 作为索引结构,叶子节点的data存放指针,也就是记录的地址.对于主键索引和辅助索引都是一样的. 2.InnoDB 也使用B+Tree作为索引结构,也别需要注意的是, ...
- 主码索引、聚集索引、非主码索引(辅助索引)、唯一索引、外键索引、复合索引、非主码索引、聚集主码(聚集索引)、单列索引、多列索引、普通索引等...
强烈建议看了第一个参考文献再来看这个篇博文,因为此处不准备讲底层数据结构的实现. 索引:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构.其 ...
最新文章
- python操作系统-PYTHON-操作系统基础
- if you are alone with your mac connected to Internet
- Bigtable的些许重点
- http://w3cschool.codecloud.net/python/python-object.html?ref=myread
- php门面理解,php 门面模式(外观模式)
- JMeter二次开发(1)-eclipse环境配置及源码编译
- property练习
- java委_java双亲委派机制及作用
- 汉字转拼音以及五笔码
- .gen格式文件读取,完成兰伯特和墨卡托投影转换
- c语言编程 设计密码锁,单片机控制安全密码锁的设计(附程序,pcb,原理图)
- 【网易互娱模拟笔试】解题记录
- Perl-LWP文档
- Mac升级Catalina,根目录下无法创建个人文件夹
- 电商52个专业名词解释大汇总
- 基于VGG19的识别中国人、韩国人、日本人分类器
- 初试-基于神经网络的植物识别
- 计算机状态oxcoooooe9,电脑蓝屏后开机显示状态Oxcoooooe9
- 深度神经网络(DNN)Deep Neural Networks 介绍
- k8s集群部署中etcd启动报错request sent was ignored (cluster ID mismatch: peer[c39bdec535db1fd5]=cdf818194e3a8c