MySQL explain 中的 rows 究竟是如何计算的?

732 阅读2分钟

这是我参与8月更文挑战的第18天,活动详情查看:8月更文挑战

今天在帮同事处理系统慢 SQL 时遇到几个疑惑的问题,在此简单记录一下,具体描述如下~

【背景铺垫】

相关表:

CREATE TABLE test_table (
  id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  name varchar(32) NOT NULL,
  PRIMARY KEY (id)
) ENGINE = InnoDB CHARSET = utf8mb4;

test_table 表记录数约 12w+

问题描述

相关 SQL:

EXPLAIN SELECT COUNT(*)FROM test_tableWHERE id >= 10534	AND id <= 15375;

疑问 1:上述 SQL 理应按 id 主键(聚簇索引)范围查找,为啥 explain 里的 rows 会多余两者之差呢?

在 SQL 结尾处增加 LIMIT 10 后,rows 数值竟然没有任何影响(觉得可能会变为: 10)。

EXPLAIN SELECT COUNT(*)FROM test_tableWHERE id >= 10000	LIMIT 10;

疑问 2:LIMIT 值不会影响 rows 的值么?

rows 究竟是怎么计算的呢?

这个 rows 在官网文档中的解释如下:

rows (JSON name: rows)

The rows column indicates the number of rows MySQL believes it must examine to execute the query.

For [InnoDB] tables, this number is an estimate, and may not always be exact.

dev.mysql.com/doc/refman/…

简单理解即:这个 rows 就是 mysql 认为估计需要检测的行数

为了探究 rows 究竟是如何算出来的,查找 MYSQL 源码来看看:

文件1sql/opt_explain_traditional.cc   
   关键部分:push(&items, column_buffer.col_rows, nil)

文件2sql/opt_explain.cc
   关键部分:select->quick->records

文件3sql/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.

简单翻译就是:这个方法仅仅根据给出的关于这个索引的条件和索引本身,来判断需要扫描多少行。

总结

MySQL Explain 里的 rows 这个值

  • 是 MySQL 认为它要检查的行数(仅做参考),而不是结果集里的行数;

  • 同时 SQL 里的 LIMIT 和这个也是没有直接关系的。

另外,很多优化手段,例如关联缓冲区和查询缓存,都无法影响到 rows 的显示。MySQL 可能不必真的读所有它估计到的行,它也不知道任何关于操作系统或硬件缓存的信息。

- END -

作者:架构精进之路,十年研发风雨路,大厂架构师,CSDN 博客专家,专注架构技术沉淀学习及分享,职业与认知升级,坚持分享接地气儿的干货文章,期待与你一起成长。
关注并私信我回复“01”,送你一份程序员成长进阶大礼包,欢迎勾搭。

Thanks for reading!