Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Waiting for table metadata lock问题处理

Waiting for table metadata lock问题处理

作者头像
老叶茶馆
发布于 2020-06-24 09:23:27
发布于 2020-06-24 09:23:27
1.8K0
举报

作者:魏新平

在使用mysql的时候,我们有时会碰到Waiting for table metadata lock的锁等待。但是这个锁等待比较特殊,在innodb_lock_waitshow engine innodb status 表里面都查不到。

该锁的影响

还是用例子来展示一下吧,更加简单直观。

代码语言:javascript
AI代码解释
复制
+-------+-----------------+-----------+------+---------+--------+---------------------------------+-----------------------------------------------------------------------+
| ID    | USER            | HOST      | DB   | COMMAND | TIME   | STATE                           | INFO                                                                  |
+-------+-----------------+-----------+------+---------+--------+---------------------------------+-----------------------------------------------------------------------+
|     1 | event_scheduler | localhost | NULL | Daemon  | 365869 | Waiting on empty queue          | NULL                                                                  |
| 13006 | root            | localhost | NULL | Query   |     35 | Waiting for table metadata lock | alter table test.t add column s int                                   |
| 13040 | root            | localhost | NULL | Query   |      0 | executing                       | select * from information_schema.processlist where command != 'sleep' |
| 13044 | root            | localhost | NULL | Query   |      4 | Waiting for table metadata lock | update test.t set b = 10 where a = 3                                  |
| 13043 | root            | localhost | NULL | Query   |     21 | Waiting for table metadata lock | select * from test.t                                                  |
+-------+-----------------+-----------+------+---------+--------+---------------------------------+-----------------------------------------------------------------------+

可以看到,如果一个表产生了Waiting for table metadata lock,那么针对该表的任何操作都会被锁住,包括select,这对生产会产生巨大的影响。我们可以通过配置参数lock_wait_timeout来减少这种锁可以等待的时长。不过最重要的还是减少这种锁等待的产生。

lock_wait_timeout

This variable specifies the timeout in seconds for attempts to acquire metadata locks. The permissible values range from 1 to 31536000 (1 year). The default is 31536000.

这个参数控制的是这个metadata锁等待可以等待的最长时间,如果超过就会报等待超时,默认是31536000秒,也就是一年,可以动态修改。

那接下来将介绍两种方法来处理这种问题。

方法一:INNODB_TRX

sql:
代码语言:javascript
AI代码解释
复制
SELECT
    t.PROCESSLIST_ID,
    t.PROCESSLIST_USER,
    t.PROCESSLIST_HOST,
    t.PROCESSLIST_DB,
    t.PROCESSLIST_STATE,
    t.PROCESSLIST_COMMAND,
    t.PROCESSLIST_TIME,
    t.PROCESSLIST_INFO,
    e.CURRENT_SCHEMA,
    group_concat(e.SQL_TEXT separator '
') as sql_text
FROM
    `performance_schema`.threads t ,
    `information_schema`.INNODB_TRX trx ,
    `performance_schema`.events_statements_history e 
WHERE
 t.thread_id = e.thread_id and 
 t.PROCESSLIST_ID = trx.trx_mysql_thread_id
group by t.THREAD_ID desc

如果从INNODB_TRX只能查到一个会话,那就算运气很好了,肯定是这个造成的。

那么如果碰到多于一个的情况呢,可以通过PROCESSLIST_INFO字段里面的sql来判断出来是哪一个。但是有些情况下,持有metadata锁的会话是在sleep状态下的。也就是说造成持有这个锁的语句已经执行过了,但是由于没有提交或者回滚,导致会话还是持有着这个锁。如果碰到这种情况,PROCESSLIST_INFO字段就可能是空的了,那就只能通过判断会话已经执行过的语句来猜了。

当然猜也不是瞎猜,是有根据的猜。mysql有一个events_statements_history表,可以通过连接这个表来查看会话执行过什么语句。如果有涉及到等待锁的表的语句就能大概猜出来是哪一个了。比如下面这个结果

代码语言:javascript
AI代码解释
复制
+----------------+------------------+------------------+----------------+-------------------+---------------------+------------------+------------------+----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
| PROCESSLIST_ID | PROCESSLIST_USER | PROCESSLIST_HOST | PROCESSLIST_DB | PROCESSLIST_STATE | PROCESSLIST_COMMAND | PROCESSLIST_TIME | PROCESSLIST_INFO | CURRENT_SCHEMA | sql_text                                                                                                                                                     |
+----------------+------------------+------------------+----------------+-------------------+---------------------+------------------+------------------+----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
|          12268 | root             | localhost        | NULL           | NULL              | Sleep               |              435 | NULL             | NULL           | select @@version_comment limit 1;select USER();begin;select * from t;select * from test.t;update t set b = 4 where a = 3;update test.t set b = 4 where a = 3 |
+----------------+------------------+------------------+----------------+-------------------+---------------------+------------------+------------------+----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+

最后的字段显示了这个会话执行过了什么语句。12268会话就执行过一个select,两个update等等语句。这很可能说明12268会话持有t表的metadata锁。一般来说杀了这个会话就可以解决问题了。

但是这个events_statements_history有一个限制,他不会存储所有执行过的语句,而是存储最新执行过的N个语句。这个N是由performance_schema_events_statements_history_size控制的,该参数是只读的,只能重启mysql生效,默认是10。如果执行过的语句超过了这个限制,那么很有可能是看不到对这个表进行修改的语句的,这个时候就需要猜了。

方法二:metadata_locks表

从mysql5.7开始,有了performance_schema.metadata_locks表,用于显示等待和持有metadata锁的会话信息。有效的简化了处理metadata锁等待的方法。

5.7版本该特性不是默认开启的,需要手动启动。8.0开始是默认开启的不需要配置。

5.7的文档

Metadata lock instrumentation uses the wait/lock/metadata/sql/mdl instrument, which is disabled by default.

8.0的文档

Metadata lock instrumentation uses the wait/lock/metadata/sql/mdl instrument, which is enabled by default.

在线开启方法
代码语言:javascript
AI代码解释
复制
UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME = 'wait/lock/metadata/sql/mdl';
在线关闭方法
代码语言:javascript
AI代码解释
复制
UPDATE performance_schema.setup_instruments
SET ENABLED = 'NO', TIMED = 'NO'
WHERE NAME = 'wait/lock/metadata/sql/mdl';
永久开启方法,

在配置文件的mysqld区块里面添加

代码语言:javascript
AI代码解释
复制
performance-schema-instrument='wait/lock/metadata/sql/mdl=ON'
sql
代码语言:javascript
AI代码解释
复制
SELECT
    t1.OBJECT_SCHEMA,
     t1.OBJECT_NAME,
    t1.LOCK_TYPE,
    t1.LOCK_STATUS,
    t2.PROCESSLIST_ID,
    t2.PROCESSLIST_USER,
    t2.PROCESSLIST_HOST,
    t2.PROCESSLIST_DB,
    t2.PROCESSLIST_COMMAND,
    t2.PROCESSLIST_STATE,
    t2.PROCESSLIST_INFO
FROM
    `performance_schema`.metadata_locks t1,
    `performance_schema`.threads t2
WHERE
    t1.owner_thread_id = t2.thread_id
AND t1.OBJECT_SCHEMA = 'test'
AND t1.OBJECT_NAME = 't'

只有开启特性以后出现的持有或者等待metadata锁的会话才会被记录。

代码语言:javascript
AI代码解释
复制
+---------------+-------------+-------------------+-------------+----------------+------------------+------------------+----------------+---------------------+---------------------------------+--------------------------------+
| OBJECT_SCHEMA | OBJECT_NAME | LOCK_TYPE         | LOCK_STATUS | PROCESSLIST_ID | PROCESSLIST_USER | PROCESSLIST_HOST | PROCESSLIST_DB | PROCESSLIST_COMMAND | PROCESSLIST_STATE               | PROCESSLIST_INFO               |
+---------------+-------------+-------------------+-------------+----------------+------------------+------------------+----------------+---------------------+---------------------------------+--------------------------------+
| test          | t           | SHARED_WRITE      | GRANTED     |          12268 | root             | localhost        | test           | Sleep               | NULL                            | NULL                           |
| test          | t           | SHARED_READ       | GRANTED     |          12268 | root             | localhost        | test           | Sleep               | NULL                            | NULL                           |
| test          | t           | SHARED_UPGRADABLE | GRANTED     |          12378 | root             | localhost        | test           | Query               | Waiting for table metadata lock | alter table t add column f int |
| test          | t           | EXCLUSIVE         | PENDING     |          12378 | root             | localhost        | test           | Query               | Waiting for table metadata lock | alter table t add column f int |
+---------------+-------------+-------------------+-------------+----------------+------------------+------------------+----------------+---------------------+---------------------------------+--------------------------------+

上面的结果中LOCK_STATUS字段表示连接对于matadata锁的持有状态,GRANTED表示持有,PENDING表示等待。很容易可以看出来12268会话持有了锁,而12378会话正在等待这个锁。通过kill 12268语句,或者让12268提交回滚都能解决这个问题。

总结

如果你的mysql还是5.6,那么只能按照先方法一来处理。如果你的mysql是5.7版本,可以先执行select * from performance_schema.setup_instruments WHERE NAME = 'wait/lock/metadata/sql/mdl';来查看是不是开启了metadata_locks表的特性,如果开启了可以直接使用方法二来处理。那如果是mysql8了,那么恭喜你,可以直接使用方法二来处理,简单快捷。一般及时提交或者尽量优化sql,缩短sql的执行时间,就可以减少Waiting for table metadata lock的出现次数了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 老叶茶馆 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【MySQL经典案例分析】 Waiting for table metadata lock
2018年某个周末,接到连续数据库的告警,看到too many connection的报错信息,基本上可以把问题定位在...
迪B哥
2018/12/06
4.4K0
MySQL5.7+查看Waiting for table metadata lock 锁情况
Waiting for table metadata lock 这个mdl锁,我们最常见,这篇先拿它开刀。
保持热爱奔赴山海
2020/07/27
3.9K0
MySQL5.7+查看Waiting for table metadata lock  锁情况
MySQL MDL锁
session A 通过 lock table 命令持有表 t 的 MDL 写锁,而 session B 的查询需要获取 MDL 读锁。所以,session B 进入等待状态。
十毛
2021/02/01
1K0
MySQL metadata lock 的A来B去
A: 为了确保事务的可串行性,服务器必须不允许一个会话对另一个会话中未完成的显式或隐式启动的事务中使用的表执行数据定义语言(DDL)语句。服务器通过在事务中使用的表上获取元数据锁,并将这些锁的释放推迟到事务结束时,从而实现这一点。表上的元数据锁可以防止对表结构的更改。这种锁定方法意味着一个会话内的事务正在使用的表不能进行DDL 的操作,表上的元数据锁可以防止对表结构的更改。这种锁定方法意味着,一个会话内的事务正在使用的表不能在DDL语句中被其他会话使用,直到事务结束。”
AustinDatabases
2019/09/18
8590
MySQL metadata lock  的A来B去
技术分享 | MySQL 的 MDL 锁解惑
网名 bisal ,具有十年以上的应用运维工作经验,目前主要从事数据库应用研发能力提升和技术管理相关的工作,Oracle ACE ,腾讯云TVP,拥有 Oracle OCM & OCP 、EXIN DevOps Master 、SCJP 等国际认证,国内首批 Oracle YEP 成员,OCMU 成员,《DevOps 最佳实践》中文译者之一,CSDN & ITPub 专家博主,公众号"bisal的个人杂货铺",长期坚持分享技术文章,多次在线上和线下分享技术主题。
爱可生开源社区
2022/05/23
1.4K0
技术分享 | MySQL 的 MDL 锁解惑
MySQL全面优化思路-基础内容
通过 top -Hp 10380 指定占用高的进程,可以看到具体是那些线程占用过高
Yuou
2022/09/26
4920
应用示例荟萃 | performance_schema全方位介绍(上)
经过前面6个篇幅的学习,相信大家对什么是performance_schema,已经初步形成了一个整体认识,但我想很多同行看完之前的文章之后可能还是一脸懵逼,今天就为大家带来performance_schema系列的最后一个篇章(全系共7个篇章),在这一期里,我们将为大家列举数十个performance_schema应用示例。下面,请跟随我们一起开始performance_schema系统的学习之旅吧。
老叶茶馆
2020/11/26
6430
技术分享 | 一招解决 MySQL 中 DDL 被阻塞的问题
之前碰到客户咨询定位 DDL 阻塞的相关问题,整理了一下方法,如何解决 DDL 被阻塞的问题。
爱可生开源社区
2023/05/17
1.1K0
深入理解MDL元数据锁
当你在MySQL中执行一条SQL时,语句并没有在你预期的时间内执行完成,这时候我们通常会登陆到MySQL数据库上查看是不是出了什么问题,通常会使用的一个命令就是 show processlist,看看有哪些session,这些session在做什么事情。当你看到 waiting for table metadata lock 时,那就是遇到MDL元数据锁了。本篇文章将会介绍MDL锁的产生与排查过程。
MySQL技术
2019/12/12
3.2K0
遇到MDL锁,如何分析和处理?
之前遇到一个DBA,在生产库上加字段,导致数据库连接数打满。原因就是MDL锁引起。下面让我来介绍一下MDL锁及其排查和处理方式。
用户10842762
2023/11/15
7691
MetaData Lock 之三
一 简介 通过前面两篇文章的介绍,相信读到这里的各位对MDL 锁已经有了比较深入的了解了,本文将结合理论知识介绍几组MDL 锁的案例。 二 常见MDL 锁的场景 1 Waiting for global read lock 我们先构造一个Waiting for global read lock场景: session1: alter table t1 add c3 bigint; //大表执行需较长时间 session2: set global read only=on; //等待 查看
用户1278550
2018/08/09
7610
技术分享 | 什么情况下 MySQL 连查询都能被阻塞?
工作中,很多开发和 DBA 可能接触较多的锁也就行锁了。对于行锁,阻塞写能理解,阻塞读实在是想不到。能阻塞读的那肯定是颗粒度更大的锁了,比如表级别的。
爱可生开源社区
2024/05/11
7240
技术分享 | 什么情况下 MySQL 连查询都能被阻塞?
alter table锁表,MySQL出现Waiting for table metadata lock的场景浅析及解决方案
在修改/增加表字段的时候,发现很慢, show processlist; 时, Waiting for table metadata lock 能一直锁很久。 官网的一段话,可以理解下 http://dev.mysql.com/doc/refman/5.5/en/metadata-locking.html 8.10.4. Metadata Locking MySQL 5.5.3 and up uses metadata locking to manage access to objects (tables,
小小科
2018/05/03
3.4K0
alter table锁表,MySQL出现Waiting for table metadata lock的场景浅析及解决方案
故障分析 | 记一次 MTS 并行复制导致的死锁排查
爱可生交付服务团队北京 DBA,对数据库及周边技术有浓厚的学习兴趣,喜欢看书,追求技术。
爱可生开源社区
2021/07/16
1.4K0
MySQL 5.7中如何定位DDL被阻塞的问题
在上篇文章《MySQL表结构变更,不可不知的Metadata Lock》中,我们介绍了MDL引入的背景,及基本概念,从“道”的层面知道了什么是MDL。下面就从“术”的层面看看如何定位MDL的相关问题。
星哥玩云
2022/08/17
8060
MySQL 5.7中如何定位DDL被阻塞的问题
【MySQL】metadata lock问题
MySQL使用DML来管理对数据库对象的并发访问,并确保数据一致性。DML不仅适用于表,还适用于模式和存储程序(过程、函数、触发器和计划的事件)
用户5522200
2020/06/11
1.7K0
生产运维脚本引发的 MDL 锁故障排查之旅
作者:何文超,分享 MySQL 和 OceanBase 相关技术博文。 个人博客【CSDN | 雅俗数据库】
爱可生开源社区
2025/05/21
2000
生产运维脚本引发的 MDL 锁故障排查之旅
MySQL Cases-MySQL找出谁持有表锁
表级锁对应的instruments(wait/lock/table/sql/handler)默认已开启,对应的consumers为performance_schema.table_handlers ,在setup_consumers中只受全局配置项global_instrumentation控制,默认已开启。所以默认情况下只要设置系统配置参数performance_schema=ON即可。下面通过一个示例来演示如何找出谁持有表级锁。
姚崇
2021/08/30
8900
架构师技能5:深入MySQL原理-Waiting for table metadata lock引发系统崩溃
我们码农平时大多数时间都在撸码或者撸码的路上,很少关注mysql的一些底层原理,当出现问题时没能力第一时间解决问题,出现问题后不去层层剖析问题产生的原因,后续也就可能无法避免或者绕开同类的问题。因此不要单纯做Ctrl+c和Ctrl+V,而是一边仰望星空(目标规划),一边脚踏实地去分析每个问题。 在mysql系列专栏里面,我深入浅出的总结了mysql相关知识,感兴趣的话可以去阅读,有问题就可以随时相互交流学习。
黄规速
2022/04/14
1.2K0
架构师技能5:深入MySQL原理-Waiting for table metadata lock引发系统崩溃
Waiting for global read lock的查杀
生产环境,假如不小心有个Waiting for global read lock 锁出现(例如flink cdc全量抽取数据),很容易造成生产事故。
保持热爱奔赴山海
2024/09/25
4760
相关推荐
【MySQL经典案例分析】 Waiting for table metadata lock
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档