Rows_examined远大于Rows_sent是引擎层低效的明确信号,表明InnoDB已浪费大量IO和CPU;主因包括索引未命中、失效、全表扫描及filesort/临时表等,需通过mysqldumpslow或awk筛选,并结合EXPLAIN验证索引使用情况。

Rows_examined 远大于 Rows_sent 是引擎层低效的明确信号
这不是“可能慢”,而是存储引擎已经实实在在浪费了大量 IO 和 CPU。InnoDB 每扫描一行,都要定位、读页、解压、判断是否满足 WHERE 条件——这些动作全在引擎层完成,和应用层响应时间无关。比值悬殊(比如 Rows_examined=100000 但 Rows_sent=1)说明 99.99% 的扫描都是白做的。
常见诱因包括:
- WHERE 条件未命中索引前缀(如复合索引 (a,b,c),只用 b = ?)
- LIKE '%abc' 导致索引失效
- 隐式类型转换(user_id INT 字段传入字符串 '123')
- 函数包裹索引列(WHERE YEAR(create_time) = 2025)
- ORDER BY 或 GROUP BY 触发 Using filesort 或临时表,即使 WHERE 很快也会推高 Rows_examined
怎么从慢日志里快速筛出这类问题语句
别人工翻日志。用 mysqldumpslow 按 Rows_examined 总和排序:
mysqldumpslow -s ar -t 10 /var/log/mysql/slow.log
或用 awk 直接筛比值 > 100 的条目:
awk '/Rows_examined:/ && /Rows_sent:/ {r=$3; s=$6; if(r/s > 100) print}' /var/log/mysql/slow.log | head -20注意前提:
- log_output 必须是 FILE(不是 TABLE)
- MySQL ≥ 5.7 才默认记录 Rows_examined;5.6 需设 long_query_time = 0 才能捕获所有高扫描语句
- 确认 slow_query_log = ON,且 slow_query_log_file 路径 MySQL 进程有写权限
验证是不是真由索引问题导致 —— 看 EXPLAIN 的 rows 和 key
EXPLAIN 输出里的 rows 字段就是优化器预估的 Rows_examined,它和慢日志里实际值通常接近。如果 EXPLAIN 显示 rows = 100000,而 key 是 NULL 或 type = ALL,基本坐实全表扫描。
关键看三点:
- key 是否为 NULL(没走索引)
- type 是否是 ALL 或 index(全表或全索引扫描)
- Extra 是否含 Using filesort 或 Using temporary(排序/分组拖累)
- 即使 key != NULL,也可能低效:检查数据分布是否倾斜(SELECT COUNT(*) FROM t WHERE indexed_col = ? 返回行数占全表 >20% 时,优化器大概率放弃走索引)
加索引不是万能解,顺序和字段选择很关键
对高 Rows_examined 语句加索引,必须严格按查询模式设计:
- 等值条件字段(=、IN)必须放复合索引最前
- 范围条件字段(>、BETWEEN)只能放最后,后面字段无法命中
- 避免在超长 VARCHAR 列上直接建索引(InnoDB 默认截断前 767 字节,innodb_large_prefix=ON 且 ROW_FORMAT=DYNAMIC 下才支持 3072 字节)
- 加索引前确认 innodb_online_alter_log_max_size 足够(默认 128MB),否则大表加索引会因临时文件写满失败
真正危险的不是 Rows_examined 绝对值高,而是本该走索引却没走——比如 WHERE id = ? 却扫了 5 万行。这种错配,往往比慢查询本身更值得警惕。


















