MySQL-定位MDL

元数据锁是server层的锁,表级锁,每执行一条DML、DDL语句时都会申请MDL锁,DML操作需要MDL读锁,DDL操作需要MDL写锁(MDL加锁过程是系统自动控制,无法直接干预,读读共享,读写互斥,写写互斥),申请MDL锁的操作会形成一个队列,队列中写锁获取优先级高于读锁。一旦出现写锁等待,不但当前操作会被阻塞,同时还会阻塞后续该表的所有操作。事务一旦申请到MDL锁后,直到事务执行完才会将锁释放。(这里有种特殊情况如果事务中包含DDL操作,mysql会在DDL操作语句执行前,隐式提交commit,以保证该DDL语句操作作为一个单独的事务存在,同时也保证元数据排他锁的释放)。

注: 支持事务的InnoDB引擎表和不支持事务的MyISAM引擎表,都会出现Metadata Lock Wait等待现象。一旦出现Metadata Lock Wait等待现象,后续所有对该表的访问都会阻塞在该等待上,导致连接堆积,业务受影响。

MDL是表锁的一种
1.执行 show processlist; ,如果 DDL 的状态是 Waiting for table metadata lock ,则意味着这个 DDL 被阻塞了。
2.定位是哪个线程导致 DDL 被阻塞的会话 sys.schema_table_lock_waits 是MySQL 5.7引入的,用来定位 DDL 被阻塞的问题。

SELECT sql_kill_blocking_connection
FROM sys.schema_table_lock_waits
WHERE blocking_lock_type <> 'SHARED_UPGRADABLE'
  AND (waiting_query LIKE 'alter%'
  OR waiting_query LIKE 'create%'
  OR waiting_query LIKE 'drop%'
  OR waiting_query LIKE 'truncate%'
  OR waiting_query LIKE 'rename%');

(1).先开启DML,后开启DDL,kill的是DML
(2).先开启DDL,在DDL未执行完之前执行DML,未测试

这种方法适用于 MySQL 5.7 和 8.0。
注意: MySQL 5.7 中,MDL 相关的 instruments 默认没有打开。

扩展手动查询:

select OBJECT_SCHEMA ,OBJECT_NAME ,LOCK_TYPE,LOCK_DURATION,LOCK_STATUS ,OWNER_THREAD_ID,OWNER_EVENT_ID from performance_schema.metadata_locks; 
# 查询thread_id为12671的线程执行的当前语句
select * from performance_schema.events_statements_current where thread_id=12671\G 
# 查询thread_id为12671的线程执行的历史语句
select * from performance_schema.events_statements_history where thread_id=12671\G 
# 查看thread_id为12671的线程信息,找到PROCESSLIST_ID,也可以直接执行 select sys.ps_thread_id(12671) 直接查看thread_id对应的processlist_id
select * from performance_schema.threads where thread_id=12671\G  
kill 对应的PROCESSLIST_ID;

select * from sys.innodb_lock_waits\G 查看行锁(记录锁)

posted @ 2023-04-19 11:31  Enzo_Ocean  阅读(46)  评论(0)    收藏  举报