当前位置: 代码网 > it编程>数据库>Mysql > MySQL 元数据锁及问题排查的解决

MySQL 元数据锁及问题排查的解决

2024年09月04日 Mysql 我要评论
"元数据"是用来描述数据对象定义的,而元数据锁(metadata lock mdl)即是加在这些定义上。通常我们认为非锁定一致性读(简单select)是不加锁的,这个是基于表内数据

"元数据"是用来描述数据对象定义的,而元数据锁(metadata lock mdl)即是加在这些定义上。通常我们认为非锁定一致性读(简单select)是不加锁的,这个是基于表内数据层面,其依然会对表的元数据加锁,保证读取数据期间表结构不会变更。

一、元数据锁简介

在事务执行过程中,mysql会对所有涉及对象的定义加上元数据锁(语句执行的时候加锁),目的是保证事务执行过程中对象定义不被修改(你不能在别人查询的时候修改表结构或者把表删了)。

对表进行dml操作时(select, update等),mysql会对表的定义施加一个共享元数据锁(s mdl),而进行ddl操作时,会施加排他元数据锁(x mdl)。dml之间的元数据锁时不会互相阻塞的,而普通用户通常只会执行dml,他们是感知不到元数据锁的。

如果dba在业务运行期间执行了ddl,那么ddl也会尝试获取元数据锁,在事务都很短小的时候,可能很快就获取到了。但如果有长事务阻塞了ddl,那么就有可能导致严重的问题。

示例:在会话1中执行下面sql:

create table t1 (id int primary key auto_increment);
begin;
select * from t1;

在这里插入图片描述

  • mysql对dml默认是自动提交的,因此每条dml语句都是独立事务,当语句执行完,元数据锁就释放了,这里通过begin显式开启事务,让select语句执行完后,事务依然存在。

另启动一个会话2,执行下面ddl语句,可以发现其被阻塞(会话迟迟不返回):

alter table t1 add name varchar(16);

在这里插入图片描述

  • ddl在执行前会隐式提交事务并释放元数据锁,这就是为什么要另一个会话发起ddl。

启动会话3,执行show processlist;命令,即可看到会话2在等待元数据锁(waiting for table metadata lock):

show processlist;

在这里插入图片描述

二、查看元数据锁

除了表,元数据锁也会加在表空间,存储过程,函数,触发器等对象上。但最常遇到的问题是我们想修改表结构,但是却被元数据锁阻塞了,导致ddl无法执行,进一步导致后续dml无法执行(业务停滞),此时需要进行人工干预。

2.1 查询元数据锁

mysql提供了performance_schema.metadata_locks用来查询具体元数据锁信息,且默认就打开了元数据锁的信息收集,直接查询即可。表中包含了持有,等待及其他中间状态的mdl数据,当锁释放时,会从表中删除。

如果没有打开元数据锁信息收集,可以执行下面的sql:

update performance_schema.setup_instruments
set enabled = 'yes', timed = 'yes'
where name = 'wait/lock/metadata/sql/mdl';

在这里插入图片描述

也可以持久化写入配置文件(需要重启):

[mysqld]
performance-schema-instrument='wait/lock/metadata/sql/mdl=on'

我们依然用第1章的示例,在执行完会话1的sql后,另开一个会话执行下面sql:

select 
l.object_schema 数据库名,
l.object_type 对象类型, 
l.object_name 对象名称,
l.lock_type 锁类型,
l.lock_duration 持续类型,
l.lock_status 锁状态,
l.owner_thread_id 线程id,
t.processlist_id 会话id,
s.sql_text
from performance_schema.metadata_locks l
join performance_schema.threads t on t.thread_id=l.owner_thread_id
join performance_schema.events_statements_current s on s.thread_id=l.owner_thread_id
where l.object_schema='test'and l.object_name='t1';

在这里插入图片描述

  • 锁状态为granted,代表成功获取了元数据锁

随后执行会话2的ddl,再次执行查询sql,可以看到锁状态pending(等待中):

在这里插入图片描述

  • 通过会话id,锁状态和sql_text三个字段,可以判断会话id为4107的select语句阻塞了alter table

2.2 常见问题

元数据锁的获取是有优先级的,x锁的优先级要高于s锁。在实际生产环境中,如果一个长事务阻塞了ddl,由于其尝试获取的是x锁(优先级高),那么它还会阻止后续dml获取s锁。即:dml => ddl阻塞 =>dml阻塞,从现象上看就是表无法执行任何操作。

在上面示例的基础上,再重新开几个会话执行下面的sql,你会发现所有类型dml都无法返回(甚至无法读):

insert into t1 values(1,'vincent');
update t1 set name='victor' where id=1;
delete from t1 where id=1;
select * from t1;

在这里插入图片描述

如果生产环境出现了ddl阻塞,你的processlist可能就是下面的样子,堆积的dml会越来越多,最后挤爆线程:

show procelist;

在这里插入图片描述

解决方案:

  • 尽量避免在业务活跃期间执行ddl,特别是有长事务的时候
  • 如果已经产生了阻塞,立刻取消ddl或将其会话kill掉,先让业务运行下去

注:online ddl在运行过程中也会短暂地获取x锁,所以并不能解决ddl阻塞问题。

到此这篇关于mysql 元数据锁及问题排查的解决的文章就介绍到这了,更多相关mysql 元数据锁内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

  • Mysql连接数的基本知识讲解

    基本知识连接总数(total connections)自mysql服务器启动以来,所有客户端建立的连接总次数,包括成功和失败的连接尝试活跃连接数(active connection…

    2024年09月04日 数据库
  • MySQL Prepared语句的具体使用

    在数据库应用中,很多sql语句都会重复执行很多次,每次执行可能只是where条件中的变量值不同,但mysql依然会解析sql语法并生成执行计划。对于这类情况,可以利用prepare…

    2024年09月04日 数据库
  • MySQL加减间隔时间函数DATE_ADD和DATE_SUB的实现

    MySQL加减间隔时间函数DATE_ADD和DATE_SUB的实现

    前言mysql中内置函数date_add 和 date_sub能对指定的时间进行增加或减少一个指定的时间间隔,返回的是一个日期。语法添加时间间隔date_add... [阅读全文]
  • MySQL虚拟列的具体使用

    MySQL虚拟列的具体使用

    在mysql中,虚拟列(也称为生成列)是一种特殊类型的表列,它不像普通列直接存储数据,而是根据其他列中的数据动态生成。虚拟列可以基于一个或多个其他列的值进行计算... [阅读全文]
  • mysql查询锁表的实现方法

    mysql查询锁表的实现方法

    今天在做数据更新的时候,发现表中数据量不大,但是更新语句执行很久都没成功,经过查询后发现是表锁死导致的,本文记录一下锁表解决步骤:1.查看表是否被锁(1)直接在... [阅读全文]
  • MySQL自连接与子查询方式

    MySQL自连接与子查询方式

    1. 自连接自连接是表自身与自身做笛卡尔积,在sql中进行条件查询,都是指定某一列或多个列之间进行关系运算,无法进行行与行之间的运算,在某些情况下需要对行与行之... [阅读全文]

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com