慢查询中关于MDL LOCK记录的变化

2024-10-07  本文已影响0人  重庆八怪

首先,这里不考虑innodb行锁,仅仅考虑MDL LOCK和DML/select 语句。我们知道到了8.0.28(包含)以后,记录慢查询的标准有变化,主要依赖的实际执行时间,而不是以前去掉了锁的时间(包含MDL LOCK和行锁)作为判定标准,具体参考,
https://www.jianshu.com/p/27547eb97d6a

以前通常通过lock_time来判断是否可能出现过innodb行锁堵塞和MDL LOCK堵塞,但是后来发现在8.0.28(包含)以后lock_time记录的时间变化了,通常并不包含innodb表的MDL LOCK时间,可以做测试如下,首先设置参数, set global long_query_time = 0,位了记录全部的满查询。

使用如下步骤,我们观察最后selet 语句的lock_time时间是否包含了MDL LOCK时间

步骤 session1 session2 session3
1. begin;select * from t1
2. alter table t1 add ic int;
3. select * from t1; (我们主要观察本语句lock time记录时间的不同)
4. commit;

其中第2步开始 session2和session3 因为mdl lock的原因不能获取到锁,直到第4步commit解锁。

8.0.28及之后的记录

# Time: 2024-10-08T17:40:48.426038+08:00
# User@Host: root[root] @ localhost []  Id:    29
# Query_time: 13.729913  Lock_time: 0.000019 Rows_sent: 2  Rows_examined: 2
SET timestamp=1728380434;
select * from t1;

注意这里的lock_time,几乎没有什么值,而这两个语句很明显的是等待在MDL LOCK下面,而lock_time几乎为0,因此在8.0.28及之后即便Lock_time为0不能说明语句没有遇到MDL LOCK

8.0.28及之前的记录,这里使用8.0.23

注意这里一定要将long_query_time 设置为0,否则如果主要等待在MDL LOCK上,去掉这部分时间后可能实际执行时间已经很短了,因此如果不设置long_query_time 为0不会记录任何慢查询。

# Time: 2024-10-08T18:02:47.417947+08:00
# User@Host: root[root] @ localhost []  Id:    19
# Query_time: 16.397964  Lock_time: 16.396849 Rows_sent: 1  Rows_examined: 1
SET timestamp=1728381751;
select * from t1;

这里我们能看到Lock_time实际上还是至少是包含了mdl lock的时间的。

大体原因

对于一般的DML和SELCET语句来讲,8.0.28之前的版本记录的lock _time的时候语句当跑到mysql_lock_tables函数的时候计算一次时间,这个时间实际上包含了MDL LOCK的时间,但是到了8.0.28(包含)以后这里发生了一些变化,仅仅记录了mysql_lock_tables函数里面消耗的时间,可以在函数找到如下几句,

ulonglong lock_start_usec = my_micro_time(); //仅仅是这一段 记录到了lock time
ulonglong lock_end_usec = my_micro_time(); //结束
thd->inc_lock_usec(lock_end_usec - lock_start_usec);//计算

但是innodb表的MDL LOCK堵塞并不包含在这个函数中,因此8.0.28及过后的MDL LOCK堵塞就不会记录了。
但是myisam的表锁是包含在其中,当我们使用myisam 测试表锁的时候会发现表锁的时间记录在里面,如下是8.0.36的测试,


image.png

myisam表记录的慢查询如下,

# Time: 2024-10-08T18:27:27.772193+08:00
# User@Host: root[root] @ localhost []  Id:    28
# Query_time: 67.663484  Lock_time: 67.636786 Rows_sent: 0  Rows_examined: 4
SET timestamp=1728383180;
delete from testmyisam;

可以看到即便是8036,myisam的表锁也包含在Lock_time中。

总结

上一篇 下一篇

猜你喜欢

热点阅读