EXPLAIN的rows只是优化器基于过时、采样粗糙、无直方图和跨列统计的估算值,并非真实扫描行数;它受统计延迟、数据倾斜、函数/模糊查询导致统计失效等影响,偏差常见。

EXPLAIN 的 rows 列不是真实扫描行数,它只是优化器基于过时、粗糙、无上下文的统计信息“猜”出来的数字——别拿它当真,尤其在数据倾斜或批量写入后。
为什么 rows 总是不准?统计信息本身就不新鲜
MySQL(尤其是 InnoDB)不会实时更新索引基数、值分布等统计信息。ANALYZE TABLE 才是唯一能强制重采样的操作,而默认情况下:
- 大批量导入 100 万行后,
rows可能还卡在旧的 5 万 -
innodb_stats_auto_recalc默认开启,但只在表变更超 10% 时才触发,且有延迟 - 刚建完一个高选择性索引,
SHOW INDEX里Cardinality仍是 0 或极低——因为采样没落到对应页
采样太糙:20 页 vs 几千万行
InnoDB 默认只采样 innodb_stats_sample_pages 个叶子页(5.7/8.0 默认都是 20),每页再随机抽几条记录。这意味着:
解析 MySQL 8.0 的 DDL 脚本,并将表结构导出为 Excel 格式。适用于用户需将 MySQL 的 `CREATE TABLE` 语句转换为结构化的 Excel 文件场景,导出内容包含字段名、数据类型、长度及精度等信息。支持多张表的批量处理,每张表对应 Excel 中的一个独立工作表。适用于数据库文档编写、数据字典生成及模式分析等任务。
- 大表中,20 页可能只覆盖 0.01% 的实际数据分布
- 两次
ANALYZE TABLE可能得出明显不同的Cardinality,rows自然浮动 - 调高到
innodb_stats_sample_pages = 100能缓解,但耗时上升明显,且仍无法解决本质问题
分布盲区:没有直方图,就等于瞎猜
MySQL 8.0+ 支持直方图,但默认不创建。没有它,优化器对非均匀字段(如 status 字段 95% 是 'active')完全无感知:
- 它按“所有值均匀分布”估算,
WHERE status = 'inactive'的rows可能被高估几十倍 - 手动创建需显式执行:
ANALYZE TABLE t UPDATE HISTOGRAM ON status WITH 16 BUCKETS - 直方图只对
=、IN等简单谓词有效;BETWEEN、>基本不受益
真正反映实际开销的是 Handler_read_first、Handler_read_next 等状态变量,不是 rows
最常被忽略的一点:即使你刚跑完 ANALYZE TABLE,只要查询里带函数(WHERE DATE(create_time) = '2026-09-01')、隐式转换或模糊前缀(LIKE '%abc'),优化器就会直接放弃使用索引统计,rows 就变成拍脑袋的粗略估算——这时候看 rows 已毫无意义。










