MariaDB InnoDB 表:如何查找导致“等待表元数据锁”的语句

问题描述 投票:0回答:2

如何确定 MariaDB 上元数据锁定信息行 (SELECT * FROM information_schema.metadata_lock_info) 中显示的线程 ID 的 SQL 语句是什么?

Server version: 10.0.15-MariaDB MariaDB Server

所有相关问题都从 MySQL 的角度深入探讨“等待表元数据锁”,但这对 MariaDB 没有帮助,因为它们的内省实现方式与我所知的不同。谷歌搜索并没有找到很多东西。

“显示完整进程列表”给出如下行:

| 57295 | main  | localhost | joints | Execute |   50 | Waiting for table metadata lock | select ...

它确实显示了该语句,但也不显示它具有锁。因此,我打开了元数据锁定信息,如此处所述 [0]。这仅提供了锁持有者的线程ID,但不提供语句:

MariaDB [joints]> SELECT * FROM information_schema.metadata_lock_info;
+-----------+--------------------------+-----------------+----------------------+--------------+----------------+
| THREAD_ID | LOCK_MODE                | LOCK_DURATION   | LOCK_TYPE            | TABLE_SCHEMA | TABLE_NAME     |
+-----------+--------------------------+-----------------+----------------------+--------------+----------------+
|     57322 | MDL_INTENTION_EXCLUSIVE  | MDL_EXPLICIT    | Global read lock     |              |                |
|     57322 | MDL_SHARED_NO_READ_WRITE | MDL_EXPLICIT    | Table metadata lock  | joints       | 16_study       |
|     57322 | MDL_INTENTION_EXCLUSIVE  | MDL_EXPLICIT    | Schema metadata lock | joints       |                |
|     57269 | MDL_SHARED_READ          | MDL_TRANSACTION | Table metadata lock  | joints       | authentication |
|     57301 | MDL_SHARED_READ          | MDL_TRANSACTION | Table metadata lock  | joints       | authentication |
|     57280 | MDL_SHARED_READ          | MDL_TRANSACTION | Table metadata lock  | joints       | authentication |
|     57317 | MDL_SHARED_READ          | MDL_TRANSACTION | Table metadata lock  | joints       | ship           |
|     57271 | MDL_SHARED_READ          | MDL_TRANSACTION | Table metadata lock  | joints       | administration |
|     57264 | MDL_SHARED_READ          | MDL_TRANSACTION | Table metadata lock  | joints       | server         |
+-----------+--------------------------+-----------------+----------------------+--------------+----------------+

我真正想要的是在锁定发生时看到这两个输出的“连接”。我没有找到连接这两个“表”中的数据的方法,因为前者似乎不是一个表。我想避免得到:

ERROR 1933 (HY000): Target is not running an EXPLAINable command

在尝试实时执行此操作时,由于线程在检查时结束。

[0] https://mariadb.com/kb/en/mariadb/metadata_lock_info/

mariadb
2个回答
1
投票

THREAD_ID
映射到
information_schema.PROCESSLIST.ID
show 
[full] processlist;
中的第一列。即:

SELECT * FROM information_schema.METADATA_LOCK_INFO AS mli
JOIN information_schema.PROCESSLIST AS pl ON mli.THREAD_ID = pl.ID

我更喜欢下面这样的东西,这样可以更容易地看到正在发生的事情(尽管换行符不能很好地与 cli 配合使用):

SELECT
  mli.THREAD_ID, mli.LOCK_MODE, mli.LOCK_TYPE, 
  CAST(GROUP_CONCAT(DISTINCT CONCAT(mli.TABLE_SCHEMA, '.', mli.TABLE_NAME) ORDER BY mli.TABLE_SCHEMA, mli.TABLE_NAME SEPARATOR '\n') AS CHAR) AS locked_tables, 
  pl.USER, pl.HOST, pl.DB, pl.COMMAND, pl.TIME, pl.STATE, pl.INFO, pl.QUERY_ID, pl.TID
FROM information_schema.METADATA_LOCK_INFO AS mli
JOIN information_schema.PROCESSLIST AS pl ON mli.THREAD_ID = pl.ID
GROUP BY mli.THREAD_ID, mli.LOCK_MODE, mli.LOCK_TYPE
ORDER BY time DESC, pl.ID;

特别有趣的是当

pl.COMMAND = 'Sleep'
表示某些连接池或其他(大部分是只读)程序正在持有带有锁的打开连接时。


0
投票

获取导致元数据锁定的查询并不简单,因为它可能已经完成,但仍然可以将违规线程发出的查询中的信息关联起来并找出来。

首先需要启用通用查询日志(https://mariadb.com/kb/en/general-query-log/)来记录线程 ID 以及在线程上执行的查询。

此外,还需要按照https://mariadb.com/kb/en/metadata-lock-info-plugin/

中所述安装METADATA_LOCK_INFO插件

然后重现锁定状态以确认锁定的线程ID,本例中

9
:

SHOW FULL PROCESSLIST;
+--+----+----...+------+-------+----+-------------------------------+----------------------------------
|Id|User|Host...|db    |Command|Time|State                          |Info                              
+--+----+----...+------+-------+----+-------------------------------+----------------------------------
|3 |root|172....|mydb01|Sleep  |3457|                               |null                              
|6 |root|172....|mydb01|Sleep  |2434|                               |null                              
|7 |root|172....|mydb01|Sleep  |664 |                               |null                              
|8 |root|172....|mydb01|Sleep  |3242|                               |null                              
|9 |root|172....|mydb01|Query  |3242|Waiting for table metadata lock|DROP INDEX mytbl01_idx1 ON mytbl01
...

但是它没有告诉有问题的线程是什么,所以让我们使用以下命令来确定它:

SELECT * FROM information_schema.metadata_lock_info;
+---------+-----------------------+...--------------------+...+------------+----------
|THREAD_ID|LOCK_MODE              |...LOCK_TYPE           |...|TABLE_SCHEMA|TABLE_NAME
+---------+-----------------------+...--------------------+...+------------+----------
|9        |MDL_BACKUP_ALTER_COPY  |...Backup lock         |...|            |          
|9        |MDL_INTENTION_EXCLUSIVE|...Schema metadata lock|...|mydb01      |          
|8        |MDL_SHARED_READ        |...Table metadata lock |...|mydb01      |mytbl01   
|8        |MDL_SHARED_WRITE       |...Table metadata lock |...|mydb01      |mytbl01   
|9        |MDL_SHARED_UPGRADABLE  |...Table metadata lock |...|mydb01      |mytbl01   
+---------+-----------------------+...--------------------+...+------------+----------
SELECT
    CONCAT('Thread ',P.ID,' executing "',P.INFO,'" IS LOCKED BY Thread ',
           M.THREAD_ID) WhoLocksWho
FROM INFORMATION_SCHEMA.PROCESSLIST P,
     INFORMATION_SCHEMA.METADATA_LOCK_INFO M
WHERE LOCATE(lcase(LOCK_TYPE), lcase(STATE))>0;
+-----------------------------------------------------------------------------+
|WhoLocksWho                                                                  |
+-----------------------------------------------------------------------------+
|Thread 9 executing "DROP INDEX mytbl01_idx1 ON mytbl01" IS LOCKED BY Thread 8|
...

这表明有问题的线程是

8

现在,有了这些信息,让我们打开常规查询日志并查找锁定的查询 (

DROP INDEX mytbl01_idx1 ON mytbl01
) 以及线程
mytbl01
对表
8
执行的查询的先前条目:

8 Query    select count(*) from mytbl01
...
9 Query    DROP INDEX mytbl01_idx1 ON mytbl01

线程

mytbl01
对表
8
执行的最后一个查询是
select count(*) from mytbl01
,这就是有问题的查询。

最后,要了解更多背景知识,请学习 https://dev.mysql.com/doc/refman/8.4/en/metadata-locking.html

© www.soinside.com 2019 - 2024. All rights reserved.