Navicat中rows不准是MySQL优化器基于采样统计的估算偏差所致:默认仅采样20页,遇数据倾斜、函数条件、隐式转换或非最左前缀查询时统计失效,须结合ANALYZE TABLE与调参innodb_stats_persistent_sample_pages=100~200(大表且低基数字段适用)并确认innodb_stats_persistent=ON方可改善。
navicat 执行计划里的 rows 列不准,不是 navicat 的问题,而是 mysql 优化器基于采样统计的估算结果本身就不精确——它反映的是“预计扫描行数”,不是实际返回行数,更不是最终结果集大小。
为什么rows值经常严重偏离实际?
因为 rows 来自 InnoDB 的索引统计信息,而这些信息是采样估算的,不是实时计数:
- 默认只采样
innodb_stats_persistent_sample_pages = 20个数据页,样本量小,遇到数据倾斜(比如 status 字段 95% 是'done')就容易失真 -
ANALYZE TABLE不会重算全表,只是更新采样页上的键值分布,误差仍可能达 ±40% - WHERE 中用了函数(如
YEAR(create_time) = 2024)、隐式类型转换(如id = '123')、或非最左前缀索引查询(索引(a,b,c)却查WHERE b = 1),优化器直接放弃使用统计,退化为粗略估算 - 嵌套循环连接下,
rows是单次内层访问的估算,会被外层行数反复乘积放大,和真实 I/O 完全脱钩
调大innodb_stats_persistent_sample_pages真有用吗?
有用,但只在特定条件下生效:
- 千万级以上的表、且有低基数字段(
status、type)或频繁范围查询时,可将该值设为100~200 - 必须配合
ANALYZE TABLE your_table才会更新统计;光改参数不执行 ANALYZE 等于没动 - 确认
innodb_stats_persistent = ON(MySQL 5.6+ 默认开启),否则统计不落盘,重启即丢 - 超大表(>5 亿行)临时设到
400要谨慎:ANALYZE 期间会加意向锁,可能阻塞写入,务必选业务低峰期
看到rows=1但实际扫了几十万行,先查什么?
这不是采样不准的问题,是优化器根本没用上统计——优先排查这些硬性失效点:
- 执行
EXPLAIN FORMAT=JSON查看used_columns和key_parts,确认 WHERE 条件是否命中索引列 - 检查是否对索引字段用了函数:
WHERE UPPER(name) = 'A'、WHERE DATE(created_at) = '2024-01-01'都会导致索引失效 - 确认 WHERE 中没有隐式转换:比如
varchar字段用数字比较(WHERE code = 123),或int字段用字符串(WHERE id = '123') - 如果是 JOIN 查询,看
type是否为ALL或index,以及possible_keys有值但key为空——说明有索引却没被选中
真正该关注的,不是rows多准,而是它为什么失效
一个稳定的 rows 值,不等于查询快;一个跳变的 rows,也不等于查询慢。关键要判断:这个估算偏差,是不是源于你写的 SQL 本身绕过了统计机制。比如看到 rows=1 但执行极慢,八成是函数导致索引失效,而不是采样页数不够——这时候调参数、跑 ANALYZE 都是白忙。


















