比想象中更复杂一点的MySQL Slow Query Log

打印 上一主题 下一主题

主题 1049|帖子 1049|积分 3147

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
1. 问题概述

在分析 Slow Query Log 时,记录下的SQL语句,明明会对一张表执行全表扫描,可为什么慢日志中的 Rows_sent 、Rows_examined 和表的真实记录数也是不一样,乃至相差N多倍。尚有一个细节就是上述的SQL语句,执行多次,在慢日志中记录下多条记录,记录之间Rows_sent 、Rows_examined也差别显着。
这是什么原因导致的呢? 
2.举例阐明

假如,有一张 product_stock的表,其全表的数据量为80201010,size 约为56G。
对全表进行count(*),在慢日志留下的记录如下
  1. # Time:2019-06-06T13:51:22.111111+08:00
  2. # User@Host hehe[hehe] @ localhost [] Id: 868686
  3. # Query_time : 39.112233 Lock_time: 0.000333 Rows_sent 1 Rows_examined: 80201010
  4. SET timestamp .....;
  5. select count(*) from product_stock;
复制代码
但是系统应用触发的慢SQL记录如下
  1. # Time:2019-06-05T14:22:22.111222+08:00
  2. # User@Host uwser[uwser] @ [XX.XX.XX.XX] Id: 667766
  3. # Query_time : 520.662233 Lock_time: 0.000296 Rows_sent 820111 Rows_examined: 820111
  4. SET timestamp .....;
  5. select * from product_stock where 1=1;
复制代码
阐明: where 1=1 ,是系统框架自动补全的,目的是防止SQL语句没有where 条件,这个是无碍的。
确信 整个语句就是全表扫描,问题是为什么它记录下来的扫描行数只是表数据的一小部门?也没有limit限制啊?
3.官方文档对慢日志的定义

The slow query log consists of SQL statements that take more than long_query_time seconds to execute and require at least min_examined_row_limit rows to be examined. The slow query log can be used to find queries that take a long time to execute and are therefore candidates for optimization.
The time to acquire the initial locks is not counted as execution time. mysqld writes a statement to the slow query log after it has been executed and after all locks have been released, so log order might differ from execution order.
• Query_time: duration
The statement execution time in seconds.
• Lock_time: duration
The time to acquire locks in seconds.
• Rows_sent: N
The number of rows sent to the client.
• Rows_examined:
The number of rows examined by the server layer (not counting any processing internal to storage engines).
这些知识对描述的迷惑没有直接帮助。还需我们继续探寻。
4. 料想

慢日志记录的行数只是整个表的一部门,那会不会是还没执行完?会不会还在执行中被取消了?才导致只是scan此中的部门,返回的行数只是已scan的部门?
比方,假如条件答应的话,整个scan过程必要10分钟,但是执行到1分钟时,因为连接参数设置或则客户端主动取消,才进行了1/10,但是这个SQL语句照旧被慢日志记录下来了,虽然它没有执行完整。
5.料想验证

为了使验证过程简朴直接,直接通过本地mysql客户端连接吧。
5.1 执行过程中,直接cancel

当然,cancel的时候,已执行的时间一定要大于自定义的慢查询时间阈值。
截取此中的一条慢日志
  1. # Time:2019-06-06T18:36:18.554477+08:00
  2. # User@Host uwser[uwser] @ [XX.XX.XX.XX] Id: 842366
  3. # Query_time : 20.662233 Lock_time: 0.000296 Rows_sent 3691064 Rows_examined: 3691064
  4. SET timestamp .....;
  5. select * from product_stock
复制代码
 cancal取消后,仍然会记录下慢日志,并且只返回已经扫描的数据(80201010中的3691064), 此种情况,验证了料想是精确的。
5.2 执行中被Kill

当然,被Kill的时候(新打开一个connection去kill即可),已执行的时间一定要大于自定义的慢查询时间阈值。
  1. # Time:2019-06-06T19:12:10.553322+08:00
  2. # User@Host uwser[uwser] @ [XX.XX.XX.XX] Id: 842366
  3. # Query_time : 50.662233 Lock_time: 0.000456 Rows_sent 10121006 Rows_examined: 10121006
  4. SET timestamp .....;
  5. select * from product_stock
复制代码
被KILL后,仍然会记录下慢日志,并且只返回已经扫描的数据(80201010中的10121006), 此种情况,验证了料想是精确的。
6.结论

1) 被Cancel 或者 被KILL后,SQL语句假如符合慢日志时间,仍然会被记录下来,虽然它没有被完整下执行完;
2)此时的查询时间、扫描行数、返回行数,是截至到被Cancel 或者 被KILL时的 已执行时间、已Rows_sent 行数和 已Rows_examined行数;
3)Query_time、Rows_sent 行数、Rows_examined,可能不是SQL语句已完整执行的结果统计,只是整个SQL过程部门进度的统计,即截至到 被Cancel 或者 被KILL节点的统计;
4)上述情况发生时,执行多次,在慢日志中记录下多条记录,记录之间差别数据差别 是因为SQL受获取执行锁、DB执行时压力情况等因素的差别,导致退出时执行进度差别,各记录间 执行时间、 Rows_sent 、Rows_examined差别也是可以明白的。
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表