navicat执行计划中rows不准,因其是mysql优化器基于innodb采样统计(默认仅20页)的估算值,非真实扫描数;大批量写入后未执行analyze table、函数/隐式转换/非最左前缀查询等会导致索引统计失效,使rows严重失真。

Navicat执行计划里的rows值为什么不准
因为rows不是真实扫描数,而是MySQL优化器基于采样统计的估算值——InnoDB不维护精确行数,只对索引键值分布做有限页采样,默认仅读20个数据页。哪怕你刚插入10万行,rows也可能还是上个月的估算结果。
哪些情况会让rows严重失真
失真不是随机波动,而是有明确触发条件:
- 大批量写入(
INSERT/UPDATE/DELETE)后没运行ANALYZE TABLE -
innodb_stats_persistent = OFF(旧版本默认),统计只存内存,MySQL重启就清零 - WHERE条件里用了函数:
WHERE YEAR(create_time) = 2024、WHERE UPPER(name) = 'A',直接让优化器放弃使用索引统计 - 隐式类型转换:
WHERE id = '123'(id是INT)、WHERE code = 123(code是VARCHAR) - 非最左前缀查询:索引是
(a,b,c),却查WHERE b = 1 AND c = 2
调大innodb_stats_persistent_sample_pages有用吗
有用,但只在特定场景下生效:
- 必须配合
ANALYZE TABLE your_table;才起作用,光改参数没用 - 确认
innodb_stats_persistent = ON(MySQL 5.6+ 默认开启),否则统计不落盘 - 对千万级表、且字段基数低(如
status只有'pending'/'done'两种值)时,可设为100~200 - 超大表(>5亿行)设到
400要谨慎:ANALYZE期间加意向锁,可能阻塞写入
看到rows=1但实际扫了几十万行,先查什么
这不是统计不准的问题,是优化器压根没用上统计——说明索引根本没生效:
- 用
EXPLAIN FORMAT=JSON看used_columns和key_parts,确认WHERE条件是否命中索引列 - 检查是否对索引字段用了函数或隐式转换(上面已列)
- 查
type是否为ALL或index,以及possible_keys有值但key为空 - JOIN场景下,
rows是单次内层访问估算,会被外层行数反复乘积放大,和真实I/O完全脱钩
rows多准,而是它为什么失效——一个跳变的rows不等于慢查询,但key=NULL或type=ALL一定意味着索引设计或SQL写法出了硬伤。











