当前位置: 首页 > 科技观察

MySQL实战笔记第02期:MySQL元数据锁

时间:2023-03-13 16:29:45 科技观察

我们在MySQL中执行DDL语句的时候,经常会发现语句并没有在你期望的时间完成。这时候我们一般会使用showfullprocesslist来查看发生了什么情况。当您看到等待表元数据锁时,您就有了元数据锁。那么元数据锁是如何产生的,应该如何避免呢?让我们从这篇文章开始了解它。1.什么是元数据锁?MDL的全称是metadatalock,即元数据锁。也可以笼统的称为字典锁。MDL的主要作用是管理对数据库对象的并发访问并确保元数据的一致性。元数据锁的适用对象包括:表、模式、过程、函数、触发器、计划事件和表空间。2.加锁规则获取规则:语句逐个(onebyone)获取元数据锁,不能同时获取,在获取过程中进行死锁检测。DML语句按照表在语句中出现的顺序获取锁。DDL语句、LOCKTABLES和其他类似语句按名称顺序获取锁,并且可能以不同的顺序获取隐式使用的表(例如也必须在外键关系中锁定的表)的锁。DDL的写锁请求优先级高于DML3,模拟加锁规则从t和t_new两张表结构相同的表开始。三个线程操作这些表:场景1线程1:LOCKTABLEtWRITE,t_newWRITE;此语句按表名顺序获取t和t_new上的写锁线程2:INSERTINTOTVALUES(1);此语句还需要获取表t上的MDL,因此处于等待状态的线程3:RENAMETABLEtTOt_old,t_newTOt;这条语句需要按表名顺序获取t、t_new、t_old上的互斥锁,所以也处于等待状态thread1:UNLOCKTABLES;此语句释放t和t_new上的写锁。线程3给t加写锁的优先级高于线程2,所以线程3先获取t上的互斥量,然后依次获取t_new和t_old上的互斥量,重命名后释放自己的锁。线程2获取t上的写锁,执行插入,然后释放它的锁。重命名操作在插入之前执行。场景2表结构相同的两张表t和new_t同样由三个线程操作线程1:LOCKTABLEtWRITE,new_tWRITE;此语句按表名顺序获取new_t和t上的写锁线程2:INSERTINTOtVALUES(1);该语句还需要获取表t上的MDL,所以处于等待状态Thread3:RENAMETABLEtTOold_t,new_tTOt;这条语句需要按照表名顺序获取new_t、old_t、t上的互斥锁,所以也处于等待状态。该语句释放t和new_t上的写锁。线程2最先发起对t的锁请求,所以线程2先获取t上的metadata写锁,执行insert操作,然后释放锁。线程3先获取new_t和old_t的互斥量,最后再请求t上的互斥量,所以线程3处于等待状态,直到线程2执行完毕。重命名操作在插入操作之后进行。4.如何监控元数据锁performance_schema.metadata_locks表记录了元数据锁的相关信息。打开方法如下:在线打开metadata_locks,操作如下:--UPDATEperformance_schema.setup_consumersSETENABLED='YES'WHERENAME='global_instrumentation';--这里的值是默认开启的,勾选确认。更新performance_schema.setup_instrumentsSETENABLED='YES'WHERENAME='wait/lock/metadata/sql/mdl';如果可以停止数据库维护,在my.cnf中添加:[mysqld]performance-schema-instrument='wait/lock/metadata/sql/mdl=ON'五、如何优化元数据锁一旦发生MDL锁,会对业务造成很大的影响,因为后续对该表的所有访问都会被阻塞,导致连接积压。我们在日常生活中尽量避免MDL锁的出现。这里有一些优化建议供参考:启用metadata_locks表记录MDL锁。设置参数lock_wait_timeout为一个小值,使阻塞端主动停止。规范交易的使用,及时提交交易,避免使用大额交易。增强的监控和警报以及时检测MDL锁定。DDL操作和备份操作在非高峰时段执行。