源码解析MySQL慢日志slow_log记录相关函数与逻辑

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 尝试源码分析MySQL慢日志slow_log的记录过程

源码解析MySQL慢日志记录相关函数与逻辑

操作环境

数据库版本:mysql-5.6.24 source code

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

以下主要函数的代码文件:

/mysql-5.6.24/sql/sql_class.h

/mysql-5.6.24/sql/sql_parse.cc

慢日志记录相关函数与逻辑

THD::update_server_status()函数

函数体

void update_server_status()

{

ulonglong end_utime_of_query= current_utime();

if (end_utime_of_query > utime_after_lock + variables.long_query_time)

server_status|= SERVER_QUERY_WAS_SLOW;

}

该函数主要进行慢查询的判断以及更新server_status,它判断慢查询的条件是:

end_utime_of_query > utime_after_lock + variables.long_query_time

其中:

end_utime_of_query来自于current_utime(),代码ulonglong end_utime_of_query= current_utime()进行了赋值。current_utime()是用来获取当前时间的,调用的是Linux操作系统(当前是linux系统)gettimeofday()函数。

utime_after_lock:这个值是指该SQL锁之后的时间,把SQL等待锁之后的时间作为真正的执行开始时间。假设SQL执行开始时间是1598532179899361(微秒),锁定时间假设进行了20秒(long_query_time为1秒)。而此处的utime_after_lock的值是1598532179899361+20秒的时间。这样变相的说明了,慢日志记录的SQL在进行耗时判断时,是不记录锁的(而MDL锁的时间是计算在内的,具体原因后面尝试讨论)。

variables.long_query_time:这是我们设置的long_query_time的时间。

所以这个函数主要是判断SQL的执行完成的时间加上long_query_time是否超过了当前时间(end_utime_of_query),以此判断是否是慢SQL,如果超过,则执行 server_status|= SERVER_QUERY_WAS_SLOW进行按位或且赋值运算(相当于server_status=server_status|SERVER_QUERY_WAS_SLOW),其中Mysql代码中定义SERVER_QUERY_WAS_SLOW值为2048,server_status是不确定的,会根据我们的SQL和使用方式进行赋值,我们测试时此处是2,则它们进行计算后,server_status值为2050(下面的log_slow_applicable()函数会用到)。

log_slow_statement()函数

函数体

void log_slow_statement(THD *thd)

{

DBUG_ENTER("log_slow_statement");

if (log_slow_applicable(thd))

log_slow_do(thd);

DBUG_VOID_RETURN;

}

update_server_status()函数判断完之后,继续执行,后面会执行log_slow_statement()函数,这个函数主要逻辑是:通过log_slow_applicable()判断该慢SQL是否可以记录到慢SQL里(具体逻辑下面说明),如果log_slow_applicable(thd)是true,则执行 log_slow_do(thd);

log_slow_applicable()函数

函数体

bool (THD *thd)

{

DBUG_ENTER("log_slow_applicable");

if (unlikely(thd->in_sub_stmt))

DBUG_RETURN(false); // Don't set time for sub stmt

if (thd->enable_slow_log)

{

bool warn_no_index= ((thd->server_status &

​ (SERVER_QUERY_NO_INDEX_USED |

​ SERVER_QUERY_NO_GOOD_INDEX_USED)) &&

​ opt_log_queries_not_using_indexes &&

​ !(sql_command_flags[thd->lex->sql_command] &

​ CF_STATUS_COMMAND));

bool log_this_query= ((thd->server_status & SERVER_QUERY_WAS_SLOW) ||

​ warn_no_index) &&

​ (thd->get_examined_row_count() >=

​ thd->variables.min_examined_row_limit);

bool suppress_logging= log_throttle_qni.log(thd, warn_no_index);

if (!suppress_logging && log_this_query)

DBUG_RETURN(true);

}

DBUG_RETURN(false);

}

该函数先判断是否开启了慢日志记录(if (thd->enable_slow_log)),如果开启,则进行如下判断:

一:判断warn_no_index是true还是false,主要判断:

​ 1, 使用thd->server_status和(SERVER_QUERY_NO_INDEX_USED|SERVER_QUERY_NO_GOOD_INDEX_USED)的值进行二进制的"位与&"运算,判断是否没有使用索引或者没有使用GOOD INDEX。其中SERVER_QUERY_NO_GOOD_INDEX_USED 值为16,SERVER_QUERY_NO_INDEX_USED值为32,thd->server_status前面已经计算过是2050。最终的运算式是:2050&(32|16),值为0。

​ 2,opt_log_queries_not_using_indexes 确认MySQL Server是否开启了log_queries_not_using_indexes参数。此处未开启,值为0。

​ 3,sql_command_flags[thd->lex->sql_command]和CF_STATUS_COMMAND)进行二进制的"位与&"运算,判断SQL的命令flag是否是CF_STATUS_COMMAND,然后进行"逻辑非 !"运算,其中sql_command_flags[thd->lex->sql_command]的值是变化的,会根据SQL类型不同而不同,此处由于我们使用的测试命令是show processlist,其值为4,CF_STATUS_COMMAND值为1U << 2(十进制是4)。最终的运算式是:4&4,值为4。进行"逻辑非 !"运算后是false。MySQL用这个条件来过滤admin_statements(slow log的参数log_slow_admin_statements)。只有当log_slow_admin_statements打开时,admin_statements进行比较时它才会为true。

最终的运算式是:0&&0&&false,值为false,这三个条件是"逻辑与&&"的关系,也就是三个条件必须全部是true,最终的warn_no_index才是true。

二:判断log_this_query是true还是false,主要判断:

​ 1,使用(thd->server_status & SERVER_QUERY_WAS_SLOW) 与warn_no_index的值进行"逻辑或||"运算。先对thd->server_status 和 SERVER_QUERY_WAS_SLOW两个的值进行二进制的"位与&"运算,其中thd->server_status值前面已经计算过为2050,SERVER_QUERY_WAS_SLOW值为2048,最终的运算式是:2050&2048,值为2048。然后再与warn_no_index进行"逻辑或||"运算,由于warn_no_index前面已经得出是false。2048||false的值为true。也就是这个表达式(thd->server_status & SERVER_QUERY_WAS_SLOW) ||warn_no_index)的值为true。

​ 2,使用thd->get_examined_row_count()与thd->variables.min_examined_row_limit比较,确认前者大于等于后者。这个主要是为了判断当前的慢查询的检索行数是否大于MySQL Server设置的变量min_examined_row_limit。由于我们测试时,min_examined_row_limit变量值并未进行设置,所以variables.min_examined_row_limit的值为0,此处表达式的结果为true。

最终的运算式是:true&&true,值为true。

三:判断是否要对慢日志进行suppress_logging,这个对应的MySQL server的log_throttle_queries_not_using_indexes 参数,由于我们测试时,其值并未设置,所以此处表达式的结果为false。

以上3个条件判断完成后,进行return的判断:

if (!suppress_logging && log_this_query)

DBUG_RETURN(true);

}

由于suppress_logging 值为false,所以!suppress_logging 值为true。log_this_query也是为true。最终条件成立,函数log_slow_applicable()函数返回true。

log_slow_do()函数

函数体

void log_slow_do(THD *thd)

{

DBUG_ENTER("log_slow_do");

THD_STAGE_INFO(thd, stage_logging_slow_query);

thd->status_var.long_query_count++;

if (thd->rewritten_query.length())

slow_log_print(thd,

​ thd->rewritten_query.c_ptr_safe(),

​ thd->rewritten_query.length());

else

slow_log_print(thd, thd->query(), thd->query_length());

DBUG_VOID_RETURN;

}

log_slow_applicable(thd)返回为true,进入log_slow_do()函数。该函数主要进行慢日志的写入操作。这个函数会调用slow_log_print()函数。

至此,一个SQL的慢日志判断过程完成。

目录
相关文章
|
27天前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
131 9
|
1月前
|
监控 安全 Apache
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
|
10天前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
MySQL事务日志-Undo Log工作原理分析
|
20天前
|
SQL 关系型数据库 MySQL
【MySQL基础篇】盘点MySQL常用四大类函数
本文介绍了MySQL中的四大类常用函数:字符串函数、数值函数、日期函数和流程函数。
【MySQL基础篇】盘点MySQL常用四大类函数
|
29天前
|
存储 关系型数据库 MySQL
double ,FLOAT还是double(m,n)--深入解析MySQL数据库中双精度浮点数的使用
本文探讨了在MySQL中使用`float`和`double`时指定精度和刻度的影响。对于`float`,指定精度会影响存储大小:0-23位使用4字节单精度存储,24-53位使用8字节双精度存储。而对于`double`,指定精度和刻度对存储空间没有影响,但可以限制数值的输入范围,提高数据的规范性和业务意义。从性能角度看,`float`和`double`的区别不大,但在存储空间和数据输入方面,指定精度和刻度有助于优化和约束。
120 5
|
1月前
|
SQL 关系型数据库 MySQL
MySQL常见函数第二期,你都用过哪些呢 ?
本期介绍了20个常用的MySQL函数,涵盖日期处理(如CURDATE()、DATE_FORMAT())、数学运算(如ABS()、ROUND())、统计分析(如COUNT()、SUM())等,帮助提高SQL查询效率和数据处理能力。希望对大家的学习有所帮助。
66 7
|
1月前
|
关系型数据库 MySQL
MySQL常见函数第一期,你都用过哪些呢 ?
本期介绍10个常用的MySQL函数:字符串连接(CONCAT)、提取子字符串(SUBSTRING)、获取字符串长度(LENGTH)、转换大小写(UPPER、LOWER)、去除空格(TRIM)、替换字符串(REPLACE)、查找子字符串位置(INSTR)、带分隔符的字符串连接(CONCAT_WS)以及获取当前日期时间(NOW)。
67 8
|
1月前
|
数据采集 关系型数据库 MySQL
MySQL常用函数:IF、SUM等用法
本文介绍了MySQL中常用的IF、SUM等函数及其用法,通过具体示例展示了如何利用这些函数进行条件判断、数值计算以及复杂查询。同时,文章还提到了CASE WHEN语句和其他常用函数,如COUNT、AVG、MAX/MIN等,强调了它们在数据统计分析、数据清洗和报表生成中的重要性。
|
1月前
|
存储 监控 安全
什么是事件日志管理系统?事件日志管理系统有哪些用处?
事件日志管理系统是IT安全的重要工具,用于集中收集、分析和解释来自组织IT基础设施各组件的事件日志,如防火墙、路由器、交换机等,帮助提升网络安全、实现主动威胁检测和促进合规性。系统支持多种日志类型,包括Windows事件日志、Syslog日志和应用程序日志,通过实时监测、告警及可视化分析,为企业提供强大的安全保障。然而,实施过程中也面临数据量大、日志管理和分析复杂等挑战。EventLog Analyzer作为一款高效工具,不仅提供实时监测与告警、可视化分析和报告功能,还支持多种合规性报告,帮助企业克服挑战,提升网络安全水平。
|
1月前
|
关系型数据库 MySQL 数据处理
【MySQL】函数
MySQL 提供了丰富的函数集,涵盖字符串处理、数值运算、日期时间操作和聚合计算等多个方面。这些函数在日常数据库操作中极为重要,通过合理使用这些函数,可以大大提高数据处理和查询的效率。用户还可以通过自定义函数,扩展 MySQL 的功能以满足特定需求。
58 3

推荐镜像

更多