MySQL源码学习:关于慢查询日志中的Rows_examined=0

最近在一个项目中DBA同学问了一个问题:为什么很多慢查询日志中显示 Rows_examined : 0?

需要说明的是, 这类慢查询语句都是类似 select count(*) from (…)t;

在说明这个问题之前,我们先指出两个相关背景:

1、MySQL的临时表,都是MyISAM的。

2、MyISAM表中的记录总数是额外存储的,count(*)的时候不需要遍历数据。

3、把count(*)转换为取一个const值这件事情,是在优化(optimize)阶段作的。

问题分析:

这个值对应于代码中的examined_row_count,用于统计每次执行过程中实际扫描的记录数。

正常的流程

查询执行过程中,每个子查询的信息都在curr_join,其中curr_join->examined_rows在每次扫一行的时候++.子查询完成后,curr_join->examined_rows累积到examined_row_count中。

哪里清0

我们上面这个语句,from内的子查询,curr_join->examined_rows是正常的,但在外部计算count的时候,上面提到的优化结果认为这个阶段是不需要扫描表的,把thd->examined_row_count给置0了。罪魁代码在JOIN::exec()中。

从代码中的注释来看,似乎是一个没有考虑细致的地方,待求证。

改进分析:

纵然有很多理由,在慢查询日志中显示的0还是不友好的,可以理解为是一个bug。

实际上从上面的分析可知,如果是复合查询中的一个环节,尤其不是第一个环节,此处清0会使显示结果出错。从当前的thd信息中可以判断出是否使用了子查询,简单一点的修改,根据thd.derived_tables信息来确定是否清0。

实际上每次执行开始之前的这个值是被reset过的,有理由怀疑这个地方实际上可以直接删除这句话。这个比较激进,要求证一下。

简单验证:

加了thd.derived_tables判断后,

方便调试起见,把所有的查询都打到slow_log了。

时间: 2024-12-03 11:10:08

MySQL源码学习:关于慢查询日志中的Rows_examined=0的相关文章

MySQL · 源码分析 · Innodb 引擎Redo日志存储格式简介

MySQL有多种日志.不同种类.不同目的的日志会记录在不同的日志文件中,它们可以帮助你找出mysqld内部发生的事情.比如错误日志:用来记录启动.运行或停止mysqld进程时出现的问题:查询日志:记录建立的客户端连接和执行的语句:二进制日志:记录所有更改数据的语句,主要用于逻辑复制:慢日志:记录所有执行时间超过long_query_time秒的所有查询或不使用索引的查询.而对MySQL中最常用的事务引擎innodb,redo日志是保证事务一致性非常重要的.本文结合MySQL版本5.6为分析源码介

MySQL源码学习:ib_logfile、bin-log与主从同步

今天研究MySQL主从同步的同事问了一个问题,如果InnoDB写完ib_logfile后,服务异常关闭.会不会由于主库能够根据ib_logfile恢复数据,而由于bin-log没写导致从库同步时少了这个事务?或者反之,bin-log写成功,而ib_logfile没有写完,导致从库执行事务,而主库不执行? 这会导致主从不一致. 本文简要说明下这个问题. 1. 写入流程 源码sql/handler.cc: ha_commit_trans { - if ((err= ht->prepare(ht, t

Mysql源码学习笔记 偷窥线程_Mysql

感觉代码有些凌乱,注释代码都写的比较随意,好像没有什么统一的规范,不同的文件中代码风格也有差异,可能Mysql经过了很多牛人的手之后,集众牛人之长吧.也可能是我见识比较浅薄,适应了自己的代码风格,井底之蛙了,总之还是怀着敬畏的心情开始咱的源码之旅吧.本人菜鸟,大神轻拍. Mysql可以启动起来了,应该怎么学习呢?总不能从main开始一步一步的看吧,Mysql作为比较底层的大型软件,涉及到数据库实现的方方面面,没有厚实的数据库理论基础和对Mysql各个模块相当的熟悉,从main开始势必会把自己引入

MySQL源码学习: concat + outfile的bug 原因分析

项目中碰到一个bug,需要将MySQL表中的数据导出,字段中间用逗号隔开. 1.复现 步骤: 版本 5.1.48 a) 准备数据 CREATE TABLE `test` ( `id` int(11) DEFAULT NULL, `data` char(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=gbk; insert into tad2 values (1,'丁\\奇'); b) select concat(id, data) from te

MySQL源码学习:InnoDB的ib_logfile写入策略

ib_logfile是InnoDB的事务日志文件.本文简要说明其写入时机.写入策略及如何保证数据安全. 1. 基本概念 a) ib_logfile文件个数由innodb_log_files_in_group配置决定,若为2,则在datadir目录下有两个文件,命令从0开始,分别为ib_logfile0和ib_logfile. b) 文件为顺序写入,当达到最后一个文件末尾时,会从第一个文件开始顺序复用. c) lsn: Log Sequence Number,是一个递增的整数. Ib_logfil

MySQL源码学习:关于整型判断的一个bug

问题: 这个bug来源于官方的一个bug报告,感谢@印风_小希 . 现象很容易描述,直接上例子. 5.1以后的版本都有此问题. CREATE TABLE `tb` ( `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, KEY `a` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into tb values (1,2),(2,5),(3,8),(4,6); select * from t

MySQL源码学习:InnoDB关于group commit的简单QA

    前天同事问了个问题,今天又再翻了下group commit.关于这个话题Kristian Nielsen有一个很详尽的系列文章(http://kristiannielsen.livejournal.com/12254.html), 有四个页面,文中有链接.这里列出一些细节,主要是对上面文章补充一下. Q:什么是group commit. A:1) 简单说就是:好几个线程写文件,然后一个线程fsync: 2) 只有事务日志(ib_logfile)用到: 3) 注意是多个线程(多用户).一个

MySQL源码学习:索引使用统计功能

今天刚刚知道Oracle有个索引统计的功能,可以统计每个索引的使用次数.作为一个Oracle的门外汉,我还是再次感叹人家做的是真细致.第二个想法就是给MySQL也加上. Percona版本的information_schema.innodb_index_stats 已经有索引的统计信息,我们就在巨人的肩膀上踩一脚了. 先来看下原来的表结构. CREATE TEMPORARY TABLE `INNODB_INDEX_STATS` ( `table_schema` varchar(192) NOT

MySQL源码学习:MySQL中禁止跨库访问的实现

 先说一下这里"跨库"的意思:当前use的是db1, 仍可以使用select * from db2.table1来访问table1表. 这样使得我们需要访问同一个MySQL下的其他表时不需要多一次use,也使得多个库间的表join这样的操作成为可能. 1. 问题背景 但有些使用场景下是有禁掉这种功能的需求.比如一些开放应用托管服务,一般给一个应用指定使用一种类型的db, 多个用户使用相同的应用,但每个用户访问自己的db.由于有复用连接的需求,使得不能给连接的mysqluser作库权限限