百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

技术分享 | mysql show processlist Time 为负数的思考

liebian365 2024-10-30 04:48 8 浏览 0 评论

作者:高鹏

文章末尾有他著作的《深入理解 MySQL 主从原理 32 讲》,深入透彻理解 MySQL 主从,GTID 相关技术知识。


一、问题来源

这是一个朋友问我的一个问题,问题如下,在 MTS 中 Worker 线程看到 Time 为负数是怎么回事,如下:



二、关于 show processlist 中的 Time

实际上 show processlist 中的信息基本都来自函数 mysqld_list_processes,也就是说每次执行 show processlist 都需要执行这个函数来进行填充。对于 Time 值来讲它来自如下信息:

Percona:time_t now= my_time(0);protocol->store_long ((thd_info->start_time > now) ? 0 : (longlong) (now - thd_info->start_time));官方版:time_t now= my_time(0);protocol->store_long ((longlong) (now - thd_info->start_time));

我们可以注意到在 Percona 的版本中对这个输出值做了优化,也就是如果出现负数的时候直接显示为 0,但是官方版中没有这样做,可能出现负数。


三、计算方式解读和测试

现在我们来看看这个简单的计算公式,实际上 now 很好理解就是服务器的当前时间,重点就在于 thd_info->start_time 的取值来自何处。实际这个时间来自于函数 THD::set_time,但是需要注意的是这个函数会进行重载,有下面三种方式:

重载 1

inlinevoid 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);...}

重载 2

 inlinevoid set_time(conststruct timeval *t) { start_time= user_time= *t; start_utime= utime_after_lock= my_micro_time();...}

重载 3

void set_time(QUERY_START_TIME_INFO *time_info){ start_time= time_info->start_time; start_utime= time_info->start_utime;}

其实简单的说就是其中有一个 start_utime,如果设置了 start_utime 那么 start_time 将会指定为 start_utime,并且在重载 1 中将会不会修改 start_time,这一点比较重要。

好了说了 3 种方式,我们来看看 Time 的计算有如下可能。

1、执行命令

如果主库执行常见的命令都会在命令发起的时候调用重载 1,设置 start_time 为命令开始执行的时间如下:

堆栈:#0 THD::set_time (this=0x7ffe7c000c90) at /mysqldata/percona-server-locks-detail-5.7.22/sql/sql_class.h:3505#1 0x00000000015c5fe8 in dispatch_command (thd=0x7ffe7c000c90, com_data=0x7fffec03fd70, command=COM_QUERY) at /mysqldata/percona-server-locks-detail-5.7.22/sql/sql_parse.cc:1247

可以看到这个函数没有实参,因此 start_time 会设置为当前时间,那 Time 的计算公式 now - thdinfo->start_time 就等于 (服务器当前时间 - 命令开始执行的时间)。

2、从库单 Sql 线程和 Worker 线程

其实不管单 Sql 线程还是 Worker 线程都是执行 Event 的,这里的 start_time 将会被设置为 Event header 中 timestamp 的时间(query event/dml event),这个时间实际就是主库命令发起的时间。如下:

堆栈:query event:
#0 THD::set_time (this=0x7ffe78000950, t=0x7ffe701ec430) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_class.h:3526#1 0x00000000018459ab in Query_log_event::do_apply_event (this=0x7ffe701ec310, rli=0x7ffe7003c050, query_arg=0x7ffe701d88a9 "BEGIN", q_len_arg=5) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/log_event.cc:4714
堆栈:dml event:#0 THD::set_time (this=0x7ffe78000950, t=0x7ffe701ed5b8) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/sql_class.h:3526#1 0x000000000185aa6e in Rows_log_event::do_apply_event (this=0x7ffe701ed330, rli=0x7ffe7003c050) at /root/mysqlall/percona-server-locks-detail-5.7.22/sql/log_event.cc:11417

我们看到这里有一个实参的传入我们看一下代码如下:

thd->set_time(&(common_header->when))

实际上就是这一行,这是我们前面说的重载 3,这样设置后 start_utime 和 start_time 都将会设置,即便调用重载 1 也不会更改, 那 Time 的计算方式 now-thd_info->start_time 就等于(从库服务器当前时间 - Event header 中的时间),但是要知道 Event header 中的时间实际也是来自于主库命令发起的时间。既然如此如果从库服务器的时间小于主库服务器的时间,那么 Time 的结果可能是负数是可能出现的,当然 Percona 版本做了优化负数将会显示为 0,如果从库服务器的时间大于主库的时间那么可能看到 Time 比较大。

因为我的测试环境都是 Percona,为了效果明显,我们来测试一下 Worker 线程 Time 很大的情况,如下设置:

主库:[root@mysqltest2 test]# dateFriNov101:40:54 CST 2019
从库:[root@gp1 log]# dateTueNov1915:58:37 CST 2019

主库随便做一个命令,然后观察如下:



3、设置 timestamp

如果手动指定 timestamp 也会影响到 Time 的计算结果,因为 start_utime 和 start_time 都将会设置,如下:

mysql> set timestamp=1572540000
堆栈:#0 THD::set_time (this=0x7ffe7c000c90, t=0x7fffec03db30) at /mysqldata/percona-server-locks-detail-5.7.22/sql/sql_class.h:3526#1 0x000000000169e509 in update_timestamp (thd=0x7ffe7c000c90, var=0x7ffe7c006860) at /mysqldata/percona-server-locks-detail-5.7.22/sql/sys_vars.cc:4966#2 0x00000000016b9a3d in Sys_var_session_special_double::session_update (this=0x2e68e20, thd=0x7ffe7c000c90, var=0x7ffe7c006860) at /mysqldata/percona-server-locks-detail-5.7.22/sql/sys_vars.h:1889

我们看到带入了实参,我们看看代码这一行如下:

 thd->set_time(&tmp);

这就是重载 2 了,这样设置后 start_utime 和 start_time 都将会设置,即便调用重载 1 也不会更改,言外之意就是设置了 timestamp 后即便执行了其他的命令 Time 也不会更新。Time 的计算方式 now - thdinfo->starttime 就等于 (服务器当前时间 - 设置的 timestamp 时间),这样的话就可能出现 Time 出现异常,比如很大或者为负数(Percona 为 0)如下:



4、空闲情况下

如果我们的会话空闲状态下那么 now-thd_info->start_time 公式中,now 会不断变大,但是 thd_info->start_time 却不会改变,因此 Time 会不断增大,等待到下一次命令到来后才会更改。


四、延伸

这里我想在说明一下如果从库开启了 log_slave_updates 的情况下,从库记录会记录来自主库的 Event,但是这些 Event 的 timestamp 和 Query Event 的 exetime 如何取值呢?

Event 的 timestamp 的取值

其实上面我已经说了,因为 start_time 将会被设置为 Event header 中 timestamp 的时间(query event/dml event),当记录 Evnet 的时候这个时间和主库基本一致,如下:



很明显我们会发现这些 Event 的 timestamp 不是本地的时间,而是主库的时间。

Query Event 的 exetime

我们先来看看这个时间的计算方式:

ulonglong micro_end_time= my_micro_time();//这里获取时间 query event my_micro_time_to_timeval(micro_end_time, &end_time);
 exec_time= end_time.tv_sec - thd_arg->start_time.tv_sec;//这里计算时间

相信对于 thd_arg->start_time 而言已经不再陌生,它就是主库命令发起的时间。我在我的《深入理解主从原理》系列中说过了,对于 Query Event 的 exetime 在 row 格式 binlog 下,DML 语句将会是第一行语句修改时间的时间,那么我们做如下定义(row 格式 DML 语句):

  • 主:主库第一行数据修改完成的服务器时间 - 主库本命令发起的时间
  • 从:从库第一行数据修改完成的服务器时间 - 主库本命令发起的时间

他们的差值就是:(从库第一行数据修改完成的服务器时间 - 主库第一行数据修改完成的服务器时间 )

同样如果我们从库的时间远远大于主库的时间,那么 exetime 也会出现异常如下:



最后:

Time 是我们平时关注的一个指标,我们经常用它来表示我的语句执行了多久,但是如果出现异常的情况我们也应该能够明白为什么,这里我将它的计算方式做了一个不完全的解释,希望对大家有帮助。当然对于主从部分或者 Event 部分可以参考我的《深入理解主从原理》系列。

相关推荐

快递查询教程,批量查询物流,一键管理快递

作为商家,每天需要查询许许多多的快递单号,面对不同的快递公司,有没有简单一点的物流查询方法呢?小编的回答当然是有的,下面随小编一起来试试这个新技巧。需要哪些工具?安装一个快递批量查询高手快递单号怎么快...

一键自动查询所有快递的物流信息 支持圆通、韵达等多家快递

对于各位商家来说拥有一个好的快递软件,能够有效的提高自己的工作效率,在管理快递单号的时候都需要对单号进行表格整理,那怎么样能够快速的查询所有单号信息,并自动生成表格呢?1、其实方法很简单,我们不需要一...

快递查询单号查询,怎么查物流到哪了

输入单号怎么查快递到哪里去了呢?今天小编给大家分享一个新的技巧,它支持多家快递,一次能查询多个单号物流,还可对查询到的物流进行分析、筛选以及导出,下面一起来试试。需要哪些工具?安装一个快递批量查询高手...

3分钟查询物流,教你一键批量查询全部物流信息

很多朋友在问,如何在短时间内把单号的物流信息查询出来,查询完成后筛选已签收件、筛选未签收件,今天小编就分享一款物流查询神器,感兴趣的朋友接着往下看。第一步,运行【快递批量查询高手】在主界面中点击【添...

快递单号查询,一次性查询全部物流信息

现在各种快递的查询方式,各有各的好,各有各的劣,总的来说,还是有比较方便的。今天小编就给大家分享一个新的技巧,支持多家快递,一次能查询多个单号的物流,还能对查询到的物流进行分析、筛选以及导出,下面一起...

快递查询工具,批量查询多个快递快递单号的物流状态、签收时间

最近有朋友在问,怎么快速查询单号的物流信息呢?除了官网,还有没有更简单的方法呢?小编的回答当然是有的,下面一起来看看。需要哪些工具?安装一个快递批量查询高手多个京东的快递单号怎么快速查询?进入快递批量...

快递查询软件,自动识别查询快递单号查询方法

当你拥有多个快递单号的时候,该如何快速查询物流信息?比如单号没有快递公司时,又该如何自动识别再去查询呢?不知道如何操作的宝贝们,下面随小编一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号若干...

教你怎样查询快递查询单号并保存物流信息

商家发货,快递揽收后,一般会直接手动复制到官网上一个个查询物流,那么久而久之,就会觉得查询变得特别繁琐,今天小编给大家分享一个新的技巧,下面一起来试试。教程之前,我们来预览一下用快递批量查询高手...

简单几步骤查询所有快递物流信息

在高峰期订单量大的时候,可能需要一双手当十双手去查询快递物流,但是由于逐一去查询,效率极低,追踪困难。那么今天小编给大家分享一个新的技巧,一次能查询多个快递单号的物流,下面一起来学习一下,希望能给大家...

物流单号查询,如何查询快递信息,按最后更新时间搜索需要的单号

最近有很多朋友在问,如何通过快递单号查询物流信息,并按最后更新时间搜索出需要的单号呢?下面随小编一起来试试吧。需要哪些工具?安装一个快递批量查询高手快递单号若干怎么快速查询?运行【快递批量查询高手】...

连续保存新单号功能解析,导入单号查询并自动识别批量查快递信息

快递查询已经成为我们日常生活中不可或缺的一部分。然而,面对海量的快递单号,如何高效、准确地查询每一个快递的物流信息,成为了许多人头疼的问题。幸运的是,随着科技的进步,一款名为“快递批量查询高手”的软件...

快递查询教程,快递单号查询,筛选更新量为1的单号

最近有很多朋友在问,怎么快速查询快递单号的物流,并筛选出更新量为1的单号呢?今天小编给大家分享一个新方法,一起来试试吧。需要哪些工具?安装一个快递批量查询高手多个快递单号怎么快速查询?运行【快递批量查...

掌握批量查询快递动态的技巧,一键查找无信息记录的两种方法解析

在快节奏的商业环境中,高效的物流查询是确保业务顺畅运行的关键。作为快递查询达人,我深知时间的宝贵,因此,今天我将向大家介绍一款强大的工具——快递批量查询高手软件。这款软件能够帮助你批量查询快递动态,一...

从复杂到简单的单号查询,一键清除单号中的符号并批量查快递信息

在繁忙的商务与日常生活中,快递查询已成为不可或缺的一环。然而,面对海量的单号,逐一查询不仅耗时费力,还容易出错。现在,有了快递批量查询高手软件,一切变得简单明了。只需一键,即可搞定单号查询,一键处理单...

物流单号查询,在哪里查询快递

如果在快递单号多的情况,你还在一个个复制粘贴到官网上手动查询,是一件非常麻烦的事情。于是乎今天小编给大家分享一个新的技巧,下面一起来试试。需要哪些工具?安装一个快递批量查询高手快递单号怎么快速查询?...

取消回复欢迎 发表评论: