读阻塞写 mysql,mysql MDL读写锁阻塞,以及online ddl造成的“插队”现象

[TOC]

127c4ba61615

image.png

为什么C等待拿锁之后,D也会阻塞?其实这里并没有解释清楚。因为如果按并发理解的话,C,D应当是同等级,都有可能拿到锁的。但C读写锁互斥,D读读不互斥,这样的话就跟上图所述相悖了。就,查了一下。

首先是MDL(metaData Lock)的概念。元数据锁是server层的锁,表级锁,主要用于隔离DML(Data Manipulation Language,数据操纵语言,如select)和DDL(Data Definition Language,数据定义语言,如改表头新增一列)操作之间的干扰。每执行一条DML、DDL语句时都会申请MDL锁,DML操作需要MDL读锁,DDL操作需要MDL写锁(MDL加锁过程是系统自动控制,无法直接干预,读读共享,读写互斥,写写互斥)

127c4ba61615

image.png

申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。(这里有种特殊情况如果事务中包含DDL操作,mysql会在DDL操作语句执行前,隐式提交commit,以保证该DDL语句操作作为一个单独的事务存在,同时也保证元数据排他锁的释放,例如id 44的语句改为,此时一旦alter语句执行完成会马上提交事务(autocommit=1),后面的select就在本次事务之外,其执行完成后不会持有读锁)

这样就能解释通为什么session C被阻塞后,session D也运行不了的原因了。

然后进入下一个问题:

127c4ba61615

image.png

我也试了一下,确实如此,加上begin之后,session D会“插队”到session C前面,也就是原本的队列结构竟然出现了 “插队”现象,???

这个问题就要涉及到online ddl了。

由于ddl读写互斥,严重影响性能,于是mysql推出了全新的online ddl概念,即通过:

拿MDL写锁

降级成MDL读锁

真正做DDL

升级成MDL写锁

释放MDL锁

5个步骤,第一步拿读锁是为确保没有其他ddl语句在执行;第三步是自己申请一块空间开始改表结构、填数据;等填好了之后,执行第四步,这期间由于持有读锁,可以确保不会有其他ddl语句造成不一致性;最后等拿到写锁,把表一替代就搞定了。

这样就看出来端倪了。上图中session A,Bcommit后,sessionC确实拿到了写锁,只不过由于锁降级,令sessionD拿到了读锁。但session D没有commit,因此session C在执行online commit到第三步后,又给阻塞了。所以就出现了类似于“插队”的现象。

如果想验证的话,可以再开一个begin;select...的session,就叫sessionE吧。然后让刚刚没commit的session D commit一下,会发现这次session C并没有阻塞

127c4ba61615

image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值