explain analyze能真实反映扫描行数,比普通explain更可靠;需清缓存、更新统计信息、仅变索引;重点看rows=xxx和loops值,结合filtered与extra判断索引有效性。

直接用 EXPLAIN ANALYZE 对比不同索引方案,能一眼看出真实扫描行数差异,比普通 EXPLAIN 更可靠——因为它是真执行、真计数,不靠预估。
先确保环境准备到位
要让对比有意义,得满足几个基本前提:
- 每次测试前清空查询缓存(
FLUSH STATUS或重启连接),避免缓存干扰实际扫描行为 - 表统计信息要最新,执行
ANALYZE TABLE your_table_name,否则预估和实际偏差会放大 - 同一查询语句,只改索引(增删或调整顺序),其他条件、写法、数据分布保持一致
用 EXPLAIN ANALYZE 获取真实扫描行数
执行带 EXPLAIN ANALYZE 的查询后,重点看输出里的 rows=xxx(实际扫描行数)和 actual time(真实耗时)。例如:
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 1001 AND status IN (1,2,5) ORDER BY created_at DESC LIMIT 10;
输出中类似这样的一行:
-> Index range scan on orders using idx_user_status (user_id=1001, status IN (1,2,5)) (cost=12.50 rows=85) (actual time=0.042..1.28 rows=72 loops=1)
这里 rows=72 就是这次查询真实扫描的索引行数,不是预估的 85。
横向对比多个索引方案
比如你有三套索引候选:
-
idx_user_id(单列) -
idx_user_status(user_id + status) -
idx_user_status_time(user_id + status + created_at)
对同一 SQL 分别执行 EXPLAIN ANALYZE,记录每种下的 rows 和 loops。若某次结果是 rows=9800 loops=1,另一组是 rows=63 loops=1,说明后者索引过滤效率高两个数量级。
特别注意 loops > 1 的情况——比如 loops=100 搭配 rows=10,实际处理了 1000 行,这种嵌套循环开销容易被忽略。
结合 filtered 和 Extra 判断是否“假走索引”
即使显示用了索引(key 非 NULL),也要看:
-
filtered值是否极低(如 -
Extra是否含Using filesort或Using temporary:意味着排序或分组没走索引,可能需要调整复合索引顺序来覆盖ORDER BY或GROUP BY
例如,idx_user_status 能减少扫描行数,但若 ORDER BY created_at 没被覆盖,仍会触发 Using filesort;而换成 idx_user_status_time 后该字样消失,就验证了扩展索引的有效性。
不复杂但容易忽略:真实扫描行数 ≠ 预估行数,只有 EXPLAIN ANALYZE 能告诉你优化器“猜得准不准”。











