为什么rows这么大,在mysql explain中---写在去acumg听讲座的前一夜

这周五下班前,发现了一个奇怪问题,大概是这个背景

一张表,结构为

Create Table: CREATE TABLE `out_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=Innodb AUTO_INCREMENT=36865 DEFAULT CHARSET=latin1

总共有37K rows的数据,数据大概是这样

+----+------+
| id | name |
+----+------+
|  1 | a    |
|  2 | b    |
|  3 | c    |
|  4 | D    |
|  5 | c    |
|  6 | c    |
|  7 | c    |
|  8 | c    |
|  9 | c    |
| 10 | a    |
+----+------+

运行了这个SQL

mysql> select id from out_table where id >10000  limit 1;
+-------+
| id    |
+-------+
| 10001 |
+-------+
1 row in set (0.00 sec)

速度也很快。

可是在运行explain的时候

mysql> explain select id from out_table where id >10000  limit 1;
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows  | Extra                    |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | out_table | range | PRIMARY       | PRIMARY | 4       | NULL | 26358 | Using where; Using index |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+

发现rows居然有,26358

查看MySQL官方文档,rows所代表的含义

Column Meaning
rows Estimate of rows to be examined

翻译过来就是,估计需要检测的行数。

可是从DBA的直觉来说,id字段为主键,且为自增属性,另外后面有个limit 1,那么无论如何rows应该不大于1才对。

那么是否explain没有考虑后面的limit 1呢?

继续运行SQL验证

mysql> explain select id from out_table where id >10000 ;
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows  | Extra                    |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+
|  1 | SIMPLE      | out_table | range | PRIMARY       | PRIMARY | 4       | NULL | 26358 | Using where; Using index |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+--------------------------+

果然后面的limit 1根本不影响rows的值

那么这个rows是怎么算出来的呢?我们翻看下MySQL源码(以5.6.23为例)。

为了避免不擅长的大段落描述,我把几个关键的文件和函数粘贴出来。

 

文件 关键部分 下一步
sql/opt_explain_traditional.cc" push(&items, column_buffer.col_rows, nil) col_rows
sql/opt_explain.cc select->quick->records records
sql/opt_range.cc check_quick_select  

而check_quick_select的功能,在MySQL源码中的注释为

Calculate estimate of number records that will be retrieved by a range scan on given index using given SEL_ARG intervals tree.

翻译过来就是,这个方法仅仅根据给出的关于这个索引的条件和索引本身,来判断需要扫描多少行。显然limit 1和这个索引是没有直接关系的。

所以新姿势,get!

 

posted @ 2018-03-10 22:40  友哥  阅读(3703)  评论(1编辑  收藏  举报