首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【c++】c++异常&&c++的异常处理详解
实际中C语言基本都是使用返回错误码的方式处理错误,部分情况下使用终止程序处理非常严重的错误
用户10925563
2024/08/06
6030
【c++】c++异常&&c++的异常处理详解
C++:异常的捕获和处理
        设想这样的场景,假设我们在看抖音的直播,这个页面有非常多的功能——>对应的不同的按键底层对应会调用不同的函数,比如说给主播刷礼物、给主播点赞点关注、和主播聊天、退出直播…… 在直播画面的运行过程中,画面一直是处在一个循环的过程中的,而我们想要去结束这个循环,就点点击退出直播的按钮,这个时候就可以跳出直播的这个页面。这个是非常合理的,但是除此之外的其他模块如果发生了错误,难道也要终止程序么??
小陈在拼命
2024/05/26
6980
C++:异常的捕获和处理
【C++航海王:追寻罗杰的编程之路】异常——错误处理方式之一
在C++编程中,异常处理是一种重要的技术,用于处理程序在运行时可能出现的错误或意外情况。异常是指在程序执行过程中发生的某种不正常的情况,例如除以零、内存访问错误或无效的输入等。传统的错误处理方式通常涉及使用错误代码或返回特殊值来指示问题,但这种方式可能会导致代码混乱、繁琐,并且容易被忽略或处理不当。
枫叶丹
2024/06/04
2510
【C++航海王:追寻罗杰的编程之路】异常——错误处理方式之一
初识C++ · 抛异常
在C语言里面,报错的方式往往是返回错误码,比如error1什么的,那么这个时候就需要程序员对照错误码的数字查找对应的错误,还有一种方式是直接终止程序,就像assert一样,所以有时候assert也成为暴力检查,那么可能有同学会觉得,这报错也没啥问题呀,但是,这里举个样例:
_lazy
2024/10/16
1720
【C++】异常,你了解了吗?
在之前的C语言处理错误时,会通过assert和错误码的方式来解决,这导致了发生错误就会直接把程序关闭,或者当调用链较长时,就会一层一层的去确定错误码,降低效率,所以c++针对处理错误,出现了异常,一起来学习!
The sky
2023/04/27
7030
【C++】异常,你了解了吗?
C++异常处理机制
实际中C语言基本都是使用返回错误码的方式处理错误,部分情况下使用终止程序处理非常严重的错误。
南桥
2024/09/20
3270
C++异常处理机制
C++缝隙间的重构史诗:异常
通过合理的异常处理机制,程序可以在遇到异常情况时,避免直接崩溃,而是采取合适的措施,如提示用户错误信息、进行数据回滚、尝试重新执行操作等,从而增强程序的健壮性和稳定性
澪贰
2025/05/06
1740
C++缝隙间的重构史诗:异常
C++异常
异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误。
用户11029129
2024/10/18
3760
C++异常
【异常】—— 我与C++的不解之缘(二十四)
试想一下,在我们之前写代码的过程中,程序运行出现了一些问题(就比如AVL树更新平衡因子的过程中,平衡因子出现了不可能的现象,这说明这个AVL树存在问题;)但是我们之前只是单纯的让程序终止,但是在以后的实践中,程序是一直运行的,所以我们不能直接将程序直接终止。
星辰与你
2025/03/02
1410
【异常】—— 我与C++的不解之缘(二十四)
【c++】异常
异常是处理错误的一种方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数直接或间接的调用者处理这个错误
用户11029103
2025/02/07
4150
【c++】异常
【C++】你了解异常的用法吗?
实际中C语言基本都是使用返回错误码的方式处理错误,部分情况下使用终止程序处理非常严重的错误。
利刃大大
2025/05/21
2200
【C++】你了解异常的用法吗?
异常--C++
有时catch到一个异常对象后,需要对错误进行分类,其中的某种异常错误需要进行特殊的处理,其他错误则重新抛出异常给外层调用链处理。捕获异常后需要重新抛出,直接 throw; 就可以把捕获的对象直接抛出。
小志biubiu
2025/02/27
2450
异常--C++
【C++】异常
1. 终止程序 ,如 assert ,缺陷:用户难以接受。如发生内存错误,除 0 错误时就会终止程序。
青衫哥
2023/10/17
4070
【C++】异常
【C++】一文带你深入理解C++异常机制
C++异常是C++编程语言中用于处理运行时错误的一种机制。它允许程序在检测到无法处理的错误条件时,通过抛出异常(使用throw关键字)来跳出正常的执行流程,并立即跳转到与该异常类型相匹配的catch代码块中进行处理。
_小羊_
2024/11/19
5330
【C++】一文带你深入理解C++异常机制
C++:异常
实际中 C 语言基本都是使用返回 错误码 的方式处理错误,部分情况下使用终止程序处理非常严重的
啊QQQQQ
2024/11/19
3270
C++:异常
【C++高阶】深入理解C++异常处理机制:从try到catch的全面解析
前言:在编程的浩瀚宇宙中,C++以其卓越的性能、强大的灵活性和对底层硬件的直接控制而著称,是无数开发者心中的瑰宝。然而,在追求高效与极致的路上,错误处理与异常管理往往成为不可忽视的重要环节。C++通过引入异常处理机制,为开发者提供了一套强大而灵活的工具,以优雅地应对程序执行过程中可能遇到的各种异常情况,从而确保程序的健壮性和可靠性
Eternity._
2024/08/09
1.5K0
【C++高阶】深入理解C++异常处理机制:从try到catch的全面解析
【C++】异常
举个最简单的例子:下面的代码中main函数中调用了func,func中调用了Division,在Divison中如果除0抛出了一个string类型的异常对象:
平凡的人1
2023/10/15
3550
【C++】异常
【C++进阶学习】第十二弹——C++ 异常处理:深入解析与实践应用
1. 异常是通过抛出对象来激活的,该对象的类型决定了应该激活那个catch的处理代码
GG Bond1
2024/08/09
3510
【C++进阶学习】第十二弹——C++ 异常处理:深入解析与实践应用
C++异常的介绍和分析
C++11:异常 1.C语言传统的处理错误的方式 与 C++的对比 传统的错误处理机制: 终止程序,如assert,缺陷:用户难以接受。如发生内存错误,除0错误时就会终止程序。 返回错误码,缺陷:需要程序员自己去查找对应的错误。如系统的很多库的接口函数都是通过把错误码 放到errno中,表示错误 C 标准库中setjmp和longjmp组合。这个不是很常用,了解一下 实际中C语言基本都是使用返回错误码的方式处理错误,部分情况下使用终止程序处理非常严重的错误。 c++处理方式 使
雪芙花
2022/10/31
9390
C++异常的介绍和分析
C++异常
异常是一种处理错误的方式,当一个函数发现自己无法处理的错误时就可以抛出异常,让函数的直接或间接的调用者处理这个错误。
有礼貌的灰绅士
2023/06/14
4780
C++异常
相关推荐
【c++】c++异常&&c++的异常处理详解
更多 >
交个朋友
加入[数据] 腾讯云技术交流站
获取数据实战干货 共享技术经验心得
加入数据技术工作实战群
获取实战干货 交流技术经验
加入[数据库] 腾讯云官方技术交流站
数据库问题秒解答 分享实践经验
换一批
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档