EXPLAIN 的 rows 值远大于实际扫描行数是因优化器基于过时或低精度统计信息估算偏差所致;可通过 ANALYZE TABLE 手动更新,必要时调高 innodb_stats_persistent_sample_pages 并确认 innodb_stats_persistent=ON。

为什么 EXPLAIN 的 rows 值远大于实际扫描行数?
这不是误报,而是 MySQL 优化器基于过时或低精度的统计信息做出的估算偏差。InnoDB 默认只在表变更约 10% 时自动触发统计信息更新(受 innodb_stats_auto_recalc 控制),且采样页数固定(innodb_stats_persistent_sample_pages 默认 20),面对数据倾斜、大表或高频写入场景,估算极易失真。
怎么手动触发更准的统计信息更新?
优先用 ANALYZE TABLE,它会强制重采样并刷新内存与磁盘(若启用了持久化统计):
ANALYZE TABLE orders;
如果表极大,可控制采样精度:
- 临时提高采样页数(会变慢但更准):
SET SESSION innodb_stats_persistent_sample_pages = 100; - 执行
ANALYZE TABLE后,再设回默认值(避免影响其他查询) - 确认是否启用持久化统计:
SHOW VARIABLES LIKE 'innodb_stats_persistent';—— 值为ON才会落盘
rows 仍不准?这些细节容易被忽略
即使手动 ANALYZE,以下情况仍会导致 rows 失真:
- WHERE 条件含函数或表达式(如
YEAR(create_time) = 2024),优化器无法利用索引统计,直接退化为全表估算 - 多列联合索引中,只用到最左前缀之外的列(如索引是
(a,b,c),但查WHERE b = 1),统计不覆盖该路径 - 使用了分区表且查询跨多个分区,统计信息按分区单独维护,优化器可能叠加估算而非实际探测
-
EXPLAIN显示的rows是“预估单次访问的行数”,不是最终结果集大小——嵌套循环连接下会反复乘积放大
要不要关掉自动统计?
不建议全局关闭 innodb_stats_auto_recalc。更稳妥的做法是:
- 对核心大表,在业务低峰期加定时任务跑
ANALYZE TABLE - 对写入频繁但查询模式固定的表,可设
innodb_stats_persistent = ON+ 调高innodb_stats_persistent_sample_pages(如 100–200) - 若发现某条慢查询始终因
rows误判走错索引,可用FORCE INDEX或优化器提示临时兜底,别只依赖统计修正
统计信息永远只是近似值,真正关键的是理解它在哪种条件下失效,以及如何结合 EXPLAIN FORMAT=JSON 里的 filtered 字段交叉验证估算逻辑。


















