MySQL的Slow_log如何记录SQL的MDL锁耗时

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: MySQL的Slow_log如何记录SQL的MDL锁耗时

操作环境

数据库版本:mysql-5.6.24 source code

操作系统版本:CentOS Linux release 7.6.1810 (Core)

现象

MySQL的慢日志判断逻辑是根据utime_after_lock 加上long_query_time的值与end_utime_of_query时间做比较判断的,要分析MDL锁在MySQL的慢日志中的记录逻辑,先看如下2个测试场景:

场景1:MDL请求正常执行完

执行请求1:

image-20200906173440367.png

执行请求2:

image-20200906173505344.png

由于请求1持有MDL锁未释放,请求2被阻塞,处于Waiting for table metadata lock状态,此时的long_query_time为10S:

image-20200906173607474.png
回滚请求1,此时请求2执行完成,查看慢日志记录情况:

image-20200906173919485.png

image-20200906173931664.png

此时,慢日志并未记录请求2的alter操作。

场景2:MDL请求被KILL

重复"MDL请求正常执行完"章节的请求1和请求2,当请求2阻塞超过10S时,手动终止alter 操作,查看慢日志的记录情况:

image-20200906191156448.png

image-20200906191212800.png

此时,慢日志记录了alter操作。并且query time为7分52秒,lock_time为0。

推测

通过上面的测试,MDL请求耗时在特定情况会计入慢日志,通过之前文章的慢日志函数分析,最终判断SQL是否是慢日志的函数为THD::update_server_status(),这里面起到关键作用的是utime_after_lock 变量。也就是上面的2种行为对应了utime_after_lock 的2种变化,当"MDL请求正常执行完"时,utime_after_lock 在SQL的执行过程中重新(较SQL开始时的初始化的赋值)做了赋值,而当"MDL请求被KILL"时,utime_after_lock 没有进行新的赋值。导致在进入THD::update_server_status()函数时,出现两种不同的现象。

调试分析

为了验证上面的推测,在该函数设置断点,复现2个现象,查看运行到该函数时,utime_after_lock 的变化:

场景1:MDL请求执行完

请求2添加索引(alter table)开始执行时间:21:00:55

请求1回滚(rollback)时间:21:1:14

THD::update_server_status()函数utime_after_lock值:21:1:14

当MDL请求正常执行完时,虽然请求2被请求1的元数据锁阻塞了很久(21:1:14减去21:00:55),但是当请求1回滚后,请求2的alter操作执行到THD::update_server_status()函数时,其utime_after_lock为21:1:14,并不是请求2的开始执行时间。

场景2:MDL请求被KILL

请求2添加索引(alter table)开始执行时间:20:52:23

请求2终止时间:20:53:10

THD::update_server_status()函数utime_after_lock值:20:52:24

当MDL请求被kill时,虽然请求2被请求1的元数据锁阻塞了很久(20:53:10减去20:52:23),但是当请求2被kill后,请求2执行到THD::update_server_status()函数时,其utime_after_lock为20:52:24,并不是请求2的终止执行时间,而与请求2的开始执行时间相近。

通过这两个结果的对比,也进一步的证明了之前推测的结论,也就导致被kill的 query会出现在慢日志中。

找到关键函数

对源码进行检索,MySQL中有三个函数会对utime_after_lock 的值进行改变:

thd_storage_lock_wait():

void thd_storage_lock_wait(THD *thd, long long value)

{

thd->utime_after_lock+= value;

}

调试该函数,发现该函数是引擎层调用,由于MDL并未进入引擎层,这不是当前问题需要关注的函数。

THD::set_time():

inline void set_time()

{

start_utime= utime_after_lock= my_micro_time();

if (user_time.tv_sec || user_time.tv_usec)

{

start_time= user_time;

}

else

my_micro_time_to_timeval(start_utime, &start_time);

#ifdef HAVE_PSI_THREAD_INTERFACE

PSI_THREAD_CALL(set_thread_start_time)(start_time.tv_sec);

#endif

}

inline void set_time(const struct timeval *t)

{

start_time= user_time= *t;

start_utime= utime_after_lock= my_micro_time();

#ifdef HAVE_PSI_THREAD_INTERFACE

PSI_THREAD_CALL(set_thread_start_time)(start_time.tv_sec);

#endif

}

调试该函数,该函数主要用于线程以及请求开始、执行过程中的start_utime、utime_after_lock等变量的初始化或者设置。也不是当前问题需要关注的函数。

THD::set_time_after_lock():

void set_time_after_lock()

{

utime_after_lock= my_micro_time();

MYSQL_SET_STATEMENT_LOCK_TIME(m_statement_psi, (utime_after_lock - start_utime));

}

调试该函数,该函数会在mysql_lock_tables()函数进行调用,这属于MySQL server层的调用,是判断MDL的utime_after_lock赋值问题要关注的函数

对THD::set_time_after_lock设置断点

通过对THD::set_time_after_lock函数设置断点,复现场景1与场景2,结果如下:

场景1:MDL请求正常执行完

在该场景下,当请求1执行rollback后,请求2停留在断点处,堆栈如下:

image.png

可以看到,mysql_lock_tables()函数会调用 THD::set_time_after_lock,mysql_lock_tables()函数调用THD::set_time_after_lock的位置在函数的最后,如下:

image-20200907004022553.png

场景2:MDL请求被KILL

在该场景下,当请求2被kill query后,请求2直接终止并提示ERROR 1317 (70100): Query execution was interrupted,不会触发断点。

结论

通过测试验证,MDL在特殊情况下计入慢日志的主要原因是没有运行到mysql_lock_tables()函数的 thd->set_time_after_lock()操作,导致utime_after_lock变量没有被正确赋值。以至于在做慢日志判断时,使用的依然是较早的(SQL开始初始化时)的utime_after_lock,导致THD::update_server_status()判断时认为是慢日志。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
8月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
1422 152
|
8月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎,提供高性价比、稳定安全的云数据库服务,适用于多种行业与业务场景。
1027 156
|
8月前
|
关系型数据库 分布式数据库 数据库
阿里云数据库收费价格:MySQL、PostgreSQL、SQL Server和MariaDB引擎费用整理
阿里云数据库提供多种类型,包括关系型与NoSQL,主流如PolarDB、RDS MySQL/PostgreSQL、Redis等。价格低至21元/月起,支持按需付费与优惠套餐,适用于各类应用场景。
|
8月前
|
SQL 运维 关系型数据库
深入探讨MySQL的二进制日志(binlog)选项
总结而言,对MySQL binlogs深度理解并妥善配置对数据库运维管理至关重要;它不仅关系到系统性能优化也是实现高可靠性架构设计必须考虑因素之一。通过精心规划与周密部署可以使得该机能充分发挥作用而避免潜在风险带来影响。
263 6
|
8月前
|
SQL 监控 关系型数据库
查寻MySQL或SQL Server的连接数,并配置超时时间和最大连接量
以上步骤提供了直观、实用且易于理解且执行的指导方针来监管和优化数据库服务器配置。务必记得,在做任何重要变更前备份相关配置文件,并确保理解每个参数对系统性能可能产生影响后再做出调节。
811 11
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
892 13
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
618 9
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
383 6
|
SQL Oracle 关系型数据库
MySQL、SQL Server和Oracle数据库安装部署教程
数据库的安装部署教程因不同的数据库管理系统(DBMS)而异,以下将以MySQL、SQL Server和Oracle为例,分别概述其安装部署的基本步骤。请注意,由于软件版本和操作系统的不同,具体步骤可能会有所变化。
1432 3

推荐镜像

更多