立即咨询
2024.02.27 | 中亦科技
一场MySQL数据库里的“交通堵塞”:MDL LOCK堵塞揭秘
今天我们要给大家揭秘一个MySQL数据库里可能发生的交通堵塞现象MDL LOCK堵塞。我们来一探究竟! 1 案发现场 LOCK TABLE READVSINSERT INTO 案例大概的截图如下: (点击可放大查看) 这里是测

今天我们要给大家揭秘一个MySQL数据库里可能发生的“交通堵塞”现象——MDL LOCK堵塞。我们来一探究竟!

1案发现场LOCK TABLE READ VS INSERT INTO

 

案例大概的截图如下:

(点击可放大查看)

这里是测试出来的,线上当时也是一个lock table read的语句和一大批insert into的语句被堵塞,当然要恢复很简单,我们可以通过2种方式,来查杀堵塞源头,如下:

  • table 级别的MDL LOCK,除非手动发送lock table,那么其持续时间通常为事务级别,而innodb_trx中记录了全部的事务(只读和读写),因此我们可以通过innodb_trx查询事务持续时间长于processlist中“Waiting for table metadata lock”最长时间的session的事务通常就是堵塞源头(当然也有例外,这个以后再讨论)。

     

  • 访问sys.schema_table_lock_waits进行判断,如果为5.7需要手动开启MDL LOCK的instrument,并且需要注意本视图只能检查table级别的MDL LOCK,也就是本例中的“Waiting for table metadata lock”。

2测试堵塞:谁动了我的INSERT?

但是在测试中,我们发现如下的执行顺序insert是可以执行,

表结构和数据
CREATE TABLE `t1` (
  `id` int(11) NOT NULL,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `a` (`a`)
)
mysql> select * from t1;
+----+------+------+
| id | a    | b    |
+----+------+------+
|  1 |    1 |    1 |
|  3 |    3 |    3 |
|  5 |    5 |    5 |
+----+------+------+
 
2.1 模拟(S1事务不提交)

 

 

查看session状态如下:

mysql> show processlist;
+----+-----------------+-----------+------+---------+------+---------------------------------+--------------------+-----------+---------------+
| Id | User            | Host      | db   | Command | Time | State                           | Info               | Rows_sent | Rows_examined |
+----+-----------------+-----------+------+---------+------+---------------------------------+--------------------+-----------+---------------+
|  1 | event_scheduler | localhost | NULL | Daemon  | 1046 | Waiting on empty queue          | NULL               |         0 |             0 |
|  3 | root            | localhost | new  | Query   |    0 | starting                        | show processlist   |         0 |             0 |
|  4 | root            | localhost | new  | Query   |  392 | Waiting for table metadata lock | lock table t1 read |         0 |             0 |
|  5 | root            | localhost | new  | Sleep   |  341 |                                 | NULL               |         0 |             0 |
+----+-----------------+-----------+------+---------+------+---------------------------------+--------------------+-----------+---------------+

(左右滑动查看更多)

这里可以看到这里只有lock table read的S2处于堵塞状态,而S3的insert的语句并没有堵塞,那么案例中的insert堵塞语句是哪里来的呢?

 

2.2 模拟(S1提交)

 

查看session状态如下:

+----+-----------------+-----------+------+---------+------+---------------------------------+-------------------------------+-----------+---------------+
| Id | User            | Host      | db   | Command | Time | State                           | Info                          | Rows_sent | Rows_examined |
+----+-----------------+-----------+------+---------+------+---------------------------------+-------------------------------+-----------+---------------+
|  1 | event_scheduler | localhost | NULL | Daemon  | 1325 | Waiting on empty queue          | NULL                          |         0 |             0 |
|  3 | root            | localhost | new  | Query   |    0 | starting                        | show processlist              |         0 |             0 |
|  4 | root            | localhost | new  | Sleep   |  671 |                                 | NULL                          |         0 |             0 |
|  5 | root            | localhost | new  | Query   |    4 | Waiting for table metadata lock | insert into t1 values( 9,9,9) |         0 |             0 |
+----+-----------------+-----------+------+---------+------+---------------------------------+-------------------------------+-----------+---------------

(左右滑动查看更多)

这个时候因为lock table read执行成功了,insert语句继续插入行则被MDL LOCK堵塞了。

 

 

3问题汇总和分析

 

  • 问题1:为什么模拟中lock table table read堵塞后,insert可以执行?

助力IT企业信创服务,和企业一起走向成功
立即领取企业福利 预约您的专属顾问