最近线上出现了 DDL执行过程中,出现死锁问题,导致系统DB访问异常,排查后,发现是DML+DDL出现了死锁问题。
MDL(MetaData Lock)就是针对于 DDL 与 DML、DQL 操作加锁,执行 DDL 自动添加写锁,执行 DML、DQL 自动添加读锁,也就是说 DML 语句可以同时执行(不考虑其他锁),而 DDL 间则会相互阻塞。
MDL不需要显式使用,在访问一个表的时候会被自动加上。
MDL的作用是保证读写的正确性。
这么个场景,如果一个查询正在遍历一个 表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果 跟表结构对不上,肯定是不行的。
因此,在MySQL 5.5版本中引入了MDL,当对一个表做增删改查操作的时候,加MDL读锁;当 要对表做结构变更操作的时候,加MDL写锁。
DDL 在执行会先创建一个临时表,先将表的数据全部移到这个临时表中,然后再将临时表替换当前表。在这个过程中如果出现读写操作就会影响最终结果出错。这个过程耗时主要在将原表的数据移到临时表的过程。
Request | Granted requests for lock |
type | S SH SR SW SWLP SU SRO SNW SNRW X |
----------+---------------------------------------------+
S | + + + + + + + + + - |
SH | + + + + + + + + + - |
SR | + + + + + + + + - - |
SW | + + + + + + - - - - |
SWLP | + + + + + + - - - - |
SU | + + + + + - + - - - |
SRO | + + + - - + + + - - |
SNW | + + + - - - + - - - |
SNRW | + + - - - - - - - - |
X | - - - - - - - - - - |
应用:session1 客户端:session2 session1:
session2:
Session1 和 Session2 相互等待,发生死锁。
原因:X锁和SW锁的相互互斥的机制导致的死锁。
两个会话互相等待,发生死锁,MySQL数据库会自动回滚其中一个事务。
1、在session1
中的查询,加上for update
, 使得session1
一开始就获取SW锁 2、将session1
的查询独立出当前事务 3、优化mysql
, 将DDL
操作改写成软提交方式, 获取不到锁后,释放已经拿到的锁,然后不断重试
按新结构创建新表 -> 将旧表数据迁移至新表 -> 重命名两个表
(三步都通过编写sql语句完成,比手动作快,第二步的数据迁移操作视情况而定)`。过程中最好在没人用的时候操作SELECT * FROM information_schema.INNODB_TRX;