
# MDL锁视图
#### MDL锁视图简介
社区版MySQL如果不打开performance_schema开关，则无法获取表元数据锁（MDL）的详细信息，但通常情况下performance_schema默认关闭，当用户遇到类似"Waiting for metadata lock"的问题而阻塞DML或DDL后，由于无法确定各个会话之间的关联关系，只能重启实例，增加了解决问题的成本，对业务产生了较大影响。
在业务场景较复杂的情况下，一旦涉及对数据库元数据的互斥操作（如DDL、LOCK TABLE等），会频繁发生操作的会话被其他会话阻塞的问题，给用户带来很大的困扰。
针对以上问题，华为云RDS for MySQL推出了MDL锁视图特性，可以查看数据库各会话持有和等待的元数据锁信息，用户可以有效进行系统诊断，优化自身业务，有效降低对业务影响。
#### MDL锁视图详解
MDL锁视图以系统表的形式呈现，该表位于"information_schema"下，表名称是"metadata_lock_info"。表结构如下所示。
```
desc information_schema.metadata_lock_info;
+---------------+-----------------------+---------+------+----------+---|
| Field         | Type                  | Null    |Key   |Default   |  Extra |
+---------------+-----------------------+---------+------+----------+---|
| THREAD_ID     | bigint(20) unsigned   | NO      |      |   0      |        |
| LOCK_STATUS   | varchar(24)           | NO      |      |          |        |
| LOCK_MODE     | varchar(24)           | YES     |      |  NULL    |        |
| LOCK_TYPE     | varchar(30)           | YES     |      |  NULL    |        |
| LOCK_DURATION | varchar(30)           | YES     |      |  NULL    |        |
| TABLE_SCHEMA  | varchar(64)           | YES     |      |  NULL    |        |
| TABLE_NAME    | varchar(64)           | YES     |      |  NULL    |        |
+---------------+-----------------------+---------+------+----------+---|
```
表1metadata_lock_info字段 
| 序号 | 字段名           | 字段定义                | 字段说明                                                                                                                                                                                                                                                                                                                                          |
|:---|:---|:---|:---|
| 0  | THREAD_ID     | bigint(20) unsigned | 会话ID。                                                                                                                                                                                                                                                                                                                                         |
| 1  | LOCK_STATUS   | varchar(24)         | MDL锁的两种状态。 - PENDING：表示会话正在等待该MDL锁。  - GRANTED：表示会话已获得该MDL锁。                                                                                           |
| 2  | LOCK_MODE     | varchar(24)         | 加锁的模式，如MDL_SHARED 、MDL_EXCLUSIVE 、MDL_SHARED_READ、MDL_SHARED_WRITE等。                                                                                                                                                                                                                                                                          |
| 3  | LOCK_TYPE     | varchar(30)         | MDL锁的类型，如Table metadata lock、Schema metadata lock、Global read lock、Tablespace lock等。                                                                                                                                                                                                                                                          |
| 4  | LOCK_DURATION | varchar(30)         | MDL锁范围，取值如下： - MDL_STATEMENT：表示语句级别。  - MDL_TRANSACTION：表示事务级别。  - MDL_EXPLICIT：表示GLOBAL级别。   |
| 5  | TABLE_SCHEMA  | varchar(64)         | 数据库名，对于部分GLOBAL级别的MDL锁，该值为空。                                                                                                                                                                                                                                                                                                                  |
| 6  | TABLE_NAME    | varchar(64)         | 表名，对于部分GLOBAL级别的MDL锁，该值为空。                                                                                                                                                                                                                                                                                                                    |
   
#### MDL锁视图使用示例
**使用场景：**长时间未提交事务，阻塞DDL，继而阻塞所有同表的操作。
表2MDL锁视图示例 
|  **表名**  |                                                                                                                                    **会话**                                                                                                                                     ||||
|  **表名**  |
|---|---|---|---|---|
| session2 | session3                                               | session4                                                 | session5                                                   |
| t1       | begin; select \* from t1; | -                                                        | -                                                          | -                                                                                               |
| t2       | -                                                      | begin; select \* from t2; | -                                                          | -                                                                                               |
| t3       | -                                                      | -                                                        | truncate table t2; (blocked) | -                                                                                               |
| t4       | -                                                      | -                                                        | -                                                          | begin; select \* from t2; (blocked) |
   
#### MDL锁视图案例分析
**问题** **描述**
用户发现对表t2执行truncate操作一直被阻塞后，业务流程中对表t2执行查询操作也全部被阻塞。
**排查分析**
- **无MDL锁视图**
  当发现DDL语句被阻塞后，执行**show processlist**查看线程信息，结果如下所示。
  ```
  show processlist;
  +------+--------+--------------+--------+-----------+----------+---|---|
  | Id   | User   |  Host        |  db    |  Command  |   Time   |   State                           |Info                     |
  +---------------+-----------------------+-----------+----------+-----------------------------------+---|
  | 2    | root   |  localhost   |  test  |  Sleep    |   73     |                                   | Null                    |
  | 3    | root   |  localhost   |  test  |  Sleep    |   63     |                                   | Null                    |
  | 4    | root   |  localhost   |  Null  |  Query    |   35     | Waiting for table metadata lock   | truncate table test.t2  |
  | 5    | root   |  localhost   |  test  |  Query    |   17     | Waiting for table metadata lock   | select * from test.t2   |
  | 6    | root   |  localhost   |  test  |  Query    |    0     | starting                          | show processlist        |
  +------+--------+--------------+--------+-----------+----------+---|---|
  ```
  上述线程列表信息显示：
  - ID=4的会话执行truncate操作时被其他会话持有的table metadata lock阻塞。
  
  - ID=5的会话执行查询操作时同样被阻塞。
  
  - 无法确定哪个会话阻塞了ID=4的会话和ID=5的会话。
  
  
  此时，如果随机KILL其他会话会给线上业务带来很大风险，因此只能等待其他会话释放该MDL锁。
  
- **使用MDL锁视图**
  执行**select \* from information_schema.metadata_lock_info**查看元数据锁信息，结果如下所示。
  ```
  select * from information_schema.metadata_lock_info;
  +-------------+-------------+--------------------------+----------------------+-------------------+----------------+----------------+
  | THREAD_ID   | LOCK_STATUS |  LOCK_MODE               | LOCK_TYPE            |  LOCK_DURATION    |  TABLE_SCHEMA  |   TABLE_NAME   |
  +-------------+-------------+--------------------------+----------------------+-------------------+----------------+----------------+
  | 2           | GRANTED     |  MDL_SHARED_READ         | Table metadata lock  |  MDL_TRANSACTION  |  test          |   t1           |
  | 3           | GRANTED     |  MDL_SHARED_READ         | Table metadata lock  |  MDL_TRANSACTION  |  test          |   t2           |
  | 4           | GRANTED     |  MDL_INTENTION_EXCLUSIVE | Global read lock     |  MDL_STATEMENT    |                |                |
  | 4           | GRANTED     |  MDL_INTENTION_EXCLUSIVE | Schema metadata lock |  MDL_TRANSACTION  |  test          |                |
  | 4           | PENDING     |  MDL_EXCLUSIVE           | Table metadata lock  |                   |  test          |   t2           |
  | 5           | PENDING     |  MDL_SHARED_READ         | Table metadata lock  |                   |  test          |   t2           |
  +-------------+-------------+--------------------------+----------------------+-------------------+----------------+----------------+
  ```
  结合**show processlist**的结果，从元数据锁视图中可以明显看出：
  上述线程信息和元数据锁视图信息显示：
  - THREAD_ID=4的会话正在等待表t2的metadata lock。
  
  - THREAD_ID=3的会话持有表t2的metadata lock，该MDL锁为事务级别，因此只要THREAD_ID=3的会话的事务不提交，THREAD_ID=4的会话将会一直阻塞。
  
  
  因此，用户只需在THREAD_ID=3的会话中执行命令**commit**或终止THREAD_ID=3的会话，便可以让业务继续运行。
  
 
