通过MySQLInnoDB表引起的死锁情况归纳分析日志
案例描述在定时脚本操作过程中,发现当备份表的SQL语句与删除部分数据的SQL语句同时运行时,MySQL将检测死锁并打印日志。
这两个SQL语句如下所示:
(1)插入backup_table SELECT * FROM source_table
(2)删除source_table其中ID > 5和titleweight<32768和jointime << daysago_1week美元
该teamuser表的表结构如下:
主键(` UID `,` ID `),
关键` k_id_titleweight_score `(` ID `,` titleweight `,`评分`),
InnoDB引擎=
这两个语句的source_table使用表如下:
死锁日志的时间点表明,在语句(1)中,当语句(2)开始运行时,死锁发生。
当MySQL检测死锁,除了检查MySQL的日志,我们可以通过SHOW INNODB STATUS G声明看MySQL客户端最后死锁的记录。因为帐单会很杂乱,最好使用传呼机少命令通过文件内容浏览查看结果,并将更加清晰。(在nopager结束)
由此产生的死锁记录如下:
根据死锁记录的结果,这两个语句确实有死锁,并且锁冲突发生在主索引索引上。那么,为什么这两个SQL语句中有锁冲突呢为什么冲突是关键的关键指标语句(2)得到了主键索引锁,为什么还要再申请一个锁
锁冲突分析
2.1 InnoDB事务和锁机制
MySQL的事务支持与MySQL服务器本身无关,但与存储引擎有关。MyISAM不支持事务,采用表锁。InnoDB支持ACID事务,行级锁和并发。MySQL的默认行为是在SQL语句都执行COMMIT语句,使每一个语句是有效地处理为一个单一的交易。
2.2两语句锁
在InnoDB默认隔离级别的事务,一般选择不被锁定,但锁定共享模式,更新和选择序列化锁定高水平。有一个例外。在这种情况下,声明(1)插入teamuser_20110121 SELECT * FROM teamuser添加表锁的表teamuser_20110121(发动机= MyISAM),并添加共享密钥的所有行的主键索引(即聚集索引)的所有teamuser行。主要的关键指标是默认使用。
声明(2)从teamuser哪里teamid = teamid美元和titleweight<32768和jointime < $ daysago_1week'is删除操作删除,这将加锁选择主键索引的行。因为前缀索引的关键` k_teamid_titleweight_score `(` teamid `,` titleweight `,`评分`)也用这种说法,它还安排相关集群的非聚集索引的锁。
2.3锁冲突的出现
因为共享锁和互斥锁是互斥的。当一方拥有一行记录的独占锁时,另一方不能拥有共享锁。同样的,如果一方拥有共享锁,对方不会获得独占锁。因此,当语句(1)和(2)同时运行,相当于两个交易会同时申请相同的记录行的锁资源,所以会有一个锁冲突。因为所有的两交易适用于主键索引,锁冲突只会对主要关键指标出现。
一句话往往是:在InnoDB,锁是逐渐获得的,除了一个SQL事务。获得一次,意味着一个事务锁由一个单独的SQL语句。在这种情况下,(2)已经锁定在主要的关键指标,以及为什么申请的主要关键指标的互斥锁吗类似地,语句(1)获得了主键索引的共享锁,为什么还要应用主键索引的共享锁。
在死锁记录中,等待锁的事务的页面没有与持有事务二锁的页218436相同,所有这两个都是。这代表什么
我的猜测是,在InnoDB存储引擎获得的行锁了一行行,一次都没有。这是证明。
死锁生成过程分析
知道InnoDB锁定过程中,唯一的办法是运行调试版本的MySQL从GDB的输出中查找结果。根据GDB的结果,由一个单一的SQL交易是从宏观的角度得到的。但是,从底层实现,它是一个一个地记录行查询并获得合格记录,即对行记录的索引锁定。
GDB结果如下所示:
复制代码代码如下所示:
(GDB)B lock_rec_lock
1在0×867120断点:文件锁/ lock0lock C线2070。
(GDB)C
持续的.
{切换到线程1168550240(LWP 5540)}
断点1,lock_rec_lock(执行= 0,模式= 5,REC = 0x2aedbe01c1 789 200
{ 2070
当前语言:自动;当前C
(GDB)C
持续的.
断点1,lock_rec_lock(执行= 0,模式= 1029,REC = 0x2aedbc80ba 200
{ 2070
(GDB)C
持续的.
断点1,lock_rec_lock(执行= 0,模式= 5,REC = 0x2aedbe01cf 789 200
{ 2070
(GDB)C
持续的.
(789 是一个非聚集索引,200 是主要索引)。(200)
GDB结果表明,语句(1)(2)将捕获记录锁定为多行,即按行获取锁。这说明语句(2)获得主键索引锁,并再次应用主键索引锁。
因为句子(1)使用主键索引,而句子(2)使用非聚集索引,两个事务的顺序不同,而锁定的过程是通过检查、添加和逐行完成的。
结果,这两个事务有一部分锁,并等待另一个锁,该锁在资源等待时发生,即死锁。在这个情况下检测到的锁冲突被发现锁定在第218436和218103页的NO上。
InnoDB会自动检测死锁和回滚事务的一个或多个交易来防止死锁的发生。我们会选择一个交易成本低,交易(1)解锁和回滚,并声明(2)继续运行,直到交易结束。
InnoDB的僵局感应
四个要素:独家死锁产生的条件:一个资源仅可每次过程;请求和保持条件:一个资源请求和阻塞的过程中,不断获得资源;不剥夺:进程已在资源端用端获得,不能强行剥夺;循环等待:一个端到端的循环等待资源形成多个过程之间的关系。
InnoDB死锁检测是两种,一是满足循环等待,还有另一种策略:锁的结构比MySQL的配置设置或锁定深度遍历的最大数目超过设定的最大深度,InnoDB会判断死锁(这是为了提高性能,一度占据了太多的资源避免交易)。在这里,我们只考虑了死锁的四个要素。
在多样性的形成僵局,但底层InnoDB分析锁定的循环等待条件造成的僵局可能只有四种形式:两台交叉应用互斥,同一个表的主键索引锁冲突,主键索引和非聚簇索引锁锁锁锁升级导致冲突,阻塞等待队列。
下面首先介绍了InnoDB的聚簇索引和非聚簇索引的数据存储形式,进而说明了在四死锁的情况。
4.1聚类指数和非聚类指数简介
聚集索引是主键索引,是根据指定的一个或多个列的值在磁盘上重新组合的数据类型。聚簇索引指向数据页的索引页的指针。非聚簇索引(即第二关键指标)不重新组织表中的数据,对该指标的顺序是独立的数据的物理排列顺序。指数通常是由B树数据结构进行描述,所以聚集索引的叶节点的数据节点,而非聚集索引的叶节点仍然是索引节点,通常是一个指向对应数据块。
在非聚集索引的叶节点InnoDB包含主键值作为一个指针。(这是为了减少在移动或数据分页。时间索引的维护)其结构如下:
当使用非聚集索引时,将根据所获得的主键值遍历群集索引,并获得相应的记录。
四例死锁4.2例
在InnoDB,锁定机构,使锁的获取通常是逐渐的,这就决定了它有可能在InnoDB发生死锁。
要共享的四种死锁锁定冲突是:不同表上相同的记录行索引锁冲突、主键索引锁冲突、主键索引锁和非聚集索引锁冲突,而锁升级则导致阻塞队列阻塞。
不同表中相同的记录行锁冲突
案例:两表,两行记录,交叉获取和应用互斥锁
条件:
a,两个事务分别在同一行的两个表和同一个表上操作。
B,锁定互斥应用程序
c,应用程序顺序不一致。
键索引锁冲突
案例:在这种情况下,冲突发生在关键索引锁上。
条件:
a,两个SQL语句,也就是说,两个事务操作同一个表,并使用不同的索引
B,锁定互斥应用程序
C、操作多行记录
d,查找记录的顺序是不一致的。
主键索引锁与非聚集索引锁冲突
案例:同一行的记录,两个事务使用不同的索引更新操作。
本案涉及的tsk_task表,这是以下领域和相关指标:
id:主键;
mon_time:监测时间;
status_id:任务状态;
指数:key_tsktask_montime2(status_id,mon_time)。
条件:
a,两个事务使用不同的索引
B,锁定互斥应用程序
c,运行同一行记录
当更新、删除操作后,表格中的数据信息被修改。由于在InnoDB存储引擎的索引数据的存储结构,不同的锁定序列将根据修改表和修改信息的差异采用索引执行。当指数是用来查找和修改记录,索引首先将加锁。然后,如果修改了主键信息,将添加主键索引锁和所有非聚集索引锁。非聚集索引列值将被添加到非聚集索引锁中。
在这种情况下,事务一使用非聚集索引查找和修改主键值。事务二使用主键索引查找和修改主键值,锁的顺序不同,导致资源循环同时等待。
锁升级引起的锁队列阻塞
案例:在同一行上,在事务中锁定升级,用另一个等待锁锁定队列阻塞,从而导致死锁。
条件:
a,两个事务操作是相同的行记录。
B,事务首先将锁应用于记录,然后升级到独占锁。
c,在申请独家锁的记录过程中的另一笔交易
一种避免死锁的方法
MySQL InnoDB提供与交易安全(酸兼容)与服从的能力存储引擎,回滚和崩溃recovery.innodb锁定在列级和还提供非锁定阅读在SELECT语句。这些功能添加到用户配置和性能。
但是,它的行锁机制也带来了死锁的风险,在设计应用程序时需要避免死锁的发生,避免死锁的方法如下:一个由单个SQL语句组成的隐式事务。
1。如果插入用…SELECT语句备份,数据量大,工作在一个单一的时间点,避免了竞争与其他SQL语句的使用资源,或选择到输出文件加LOAD DATA INFILE插入的选择,它不仅速度快,而且不需要锁定
2。一个交易,锁定一个记录集,其运算结果设置应尽量短,以免占用太多的资源,在一次冲突被其他事务处理记录。
三.更新或删除表数据,SQL语句的条件是主键或索引,避免两个交叉并导致死锁。当WHERE子句更复杂时,它仅由SQL获得,然后用于UPDATE语句中。
4的嵌套表。SQL语句不是太多,它可以拆分和拆分,同时避免资源和资源的等待,从而导致与其他事务的冲突。
5、定点运行脚本,避免在同一时间点在同一个表上读写多个脚本,特别注意大锁和大量数据的语句。
6。应用程序增加了死锁的判断,如果事务结束,则重新运行事务以减少对函数的影响。