MySQL执行计划里那个rows到底代表啥,你真搞明白过没?
- 问答
- 2026-01-01 15:17:29
- 4
MySQL官方文档、高性能MySQL、数据库内核探秘、多位DBA技术博客经验总结)
MySQL执行计划里的rows字段,很多人第一眼觉得很简单——不就是预估要扫描的行数嘛,但真要深究下去,这个问题能问倒不少老司机,它背后牵扯到MySQL优化器怎么猜、凭什么这么猜、以及猜得准不准的灵魂三问。
最直接的回答:rows是优化器根据表统计信息,预估的在每一步操作中需要检查的记录条数,注意这几个关键词:“预估”、“统计信息”、“检查”,它不是你查询结果的行数,也不是最终输出的行数,而是MySQL认为为了完成你这步操作,需要从存储引擎里读取多少行数据来做判断。
举个例子,你有个查询带WHERE id > 100,执行计划里如果显示rows是500,意思是优化器翻了翻自己的小本本(统计信息),觉得表里大概有500条记录满足id > 100这个条件,它是个估算值,不是精确值,MySQL不会为了生成执行计划先去实际扫一遍表数数,那样成本太高了。

这个“小本本”—— 也就是统计信息,是哪来的呢?(来源:MySQL官方文档关于InnoDB统计信息的说明)对于InnoDB表,主要来自一种叫采样统计的机制,InnoDB会选取表的一些数据页(默认是20个页),分析这些页上的数据分布,然后推算出整个表的概况,这就带来了第一个不准确的原因:采样不一定能代表全体,如果你的数据分布不均匀,比如id>100的数据恰好都集中在没被采样的页上,优化器的估计就会严重偏离。
rows的值出现在执行计划的每一行,它代表的是当前这一步的预估行数,这点非常关键。(来源:《高性能MySQL》中关于EXPLAIN输出行的解释)比如你看到两个表JOIN的执行计划: 第一行是驱动表,rows是1000; 第二行是被驱动表,rows是1。 这里的1000,是优化器估计从驱动表里会取出1000条符合条件的记录,而那1,是针对驱动表每一条记录,去被驱动表里查询时,预估每次能匹配到的平均记录数,整个嵌套循环JOIN操作,大致的检查次数是1000 * 1 = 1000次,如果这个“1”估错了,实际是10,那总成本就翻了10倍,性能差异就出来了。
rows的估算,严重依赖于索引的选择性。(来源:多位DBA技术博客中分析的索引与基数关系)选择性好的索引(比如唯一索引),能让rows值非常接近1,因为通过索引能精准定位到很少的记录,如果一个字段的值几乎都一样(比如性别字段),那即使有索引,rows值也会很大,因为优化器觉得你要扫描很多行。

为什么我们说rows的准确性至关重要?(来源:《数据库内核探秘》中关于优化器成本模型的内容)因为MySQL的优化器本质上是个成本优化器,它会给各种操作(读磁盘、读内存、比较数据)分配一个成本值,而rows是计算这些成本的核心输入,读取一行数据的成本是多少,然后乘以rows,就得到这步操作的总成本,优化器会比较不同执行路径(比如用A索引还是用B索引)的总成本,然后选一个它认为最便宜的。
当你发现一个查询慢,看执行计划时,如果发现某个步骤的实际行数(可以通过实际执行后对比)和rows预估的相差十倍百倍,那基本就找到了病根——优化器基于错误的信息做出了错误的决策,比如它本来应该走索引A,但因为A索引的统计信息过时了,rows估大了,导致它误以为全表扫描更划算。
怎么让rows更准一点?(来源:MySQL官方手册关于ANALYZE TABLE的说明)可以用ANALYZE TABLE命令来重新收集表的统计信息,但要注意,这命令会锁表(在某些版本和条件下),而且采样统计的天生缺陷依然存在,在MySQL 8.0里,引入了更先进的直方图(Histogram)统计信息,可以对没有索引的列的数据分布进行更细致的描述,这在一定程度上改善了非索引列条件查询的rows预估准确性。
MySQL执行计划里的rows,不是一个简单的数字,它是优化器基于采样统计信息,对查询工作量的一种“猜测”,这个猜测的准不准,直接决定了查询计划的优劣,理解它,是理解MySQL如何工作、如何调优的重要一步,下次再看执行计划,不妨多问一句:这个rows,它猜得靠谱吗?
本文由雪和泽于2026-01-01发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://www.haoid.cn/wenda/72522.html
