all 表示全表扫描,需检查缺失索引或索引失效;using filesort/temporary 说明排序分组未走索引;key_len 偏小反映联合索引未用全;rows 是预估扫描行数,偏差大时需 analyze table。

EXPLAIN 输出中 type 字段为 ALL 说明全表扫描,优先检查是否缺失索引
当 type 是 ALL,MySQL 正在逐行读取整张表,这是性能杀手。常见于 WHERE 条件列没建索引、或用了函数/表达式导致索引失效(比如 WHERE YEAR(created_at) = 2023)。
- 先用
SHOW CREATE TABLE确认 WHERE / JOIN / ORDER BY 涉及的字段是否有索引 - 避免在索引列上使用函数、类型隐式转换(如字符串字段用数字比较:
WHERE status = 1而 status 是VARCHAR) - 联合索引要注意最左前缀:查询只用后缀列(如索引是
(a,b,c),但 WHERE 只有c = ?)不会命中
Extra 字段出现 Using filesort 或 Using temporary 就意味着排序/分组没走索引
Using filesort 表示 MySQL 需额外排序步骤;Using temporary 表示创建了临时表(常见于 GROUP BY + 非索引列、DISTINCT + 多列、UNION)。这两者都容易拖慢查询,尤其数据量大时。
- ORDER BY 字段必须包含在索引中,且顺序与索引定义一致(如索引
(user_id, created_at),则ORDER BY user_id, created_at可用,反过来不行) - GROUP BY 尽量复用索引顺序,避免 SELECT 中出现非 GROUP BY 的非聚合字段(会强制 Using temporary)
- 覆盖索引能同时解决 filesort 和 temporary:把 SELECT 列也加入索引末尾,让 MySQL 直接从索引取数
key_len 值比预期小,说明联合索引只用到了前缀部分
key_len 显示 MySQL 实际使用的索引字节数。它能帮你判断联合索引用了几列、是否因类型或 NULL 属性多占了字节(比如 VARCHAR(255) 字段即使只存 3 个字符,也会按最大长度+长度标识计算)。
- 对比
SHOW INDEX中该索引各列的长度总和,若key_len明显偏小,说明后面列没参与查找 - 注意 NULL 列会额外占用 1 字节,所以允许 NULL 的 INT 字段 key_len 是 5,而非 NULL 的是 4
- 如果 WHERE 用了
IN或范围条件(, <code>BETWEEN),其后的联合索引列通常失效 —— 这是 key_len 突然变小的主因
rows 值远大于实际返回结果数,说明执行计划预估偏差大,可能需 ANALYZE TABLE
rows 是优化器估算的扫描行数,不是最终结果行数。它依赖统计信息,而 InnoDB 的统计是采样估算,表数据大更新频繁时容易过期。
- 执行
ANALYZE TABLE table_name强制刷新统计信息,有时能让优化器选对索引 - 如果加了 FORCE INDEX 却发现
rows暴涨,说明强制指定反而让优化器绕开了更优路径 - 注意:EXPLAIN 不执行语句,所以
rows是预估值,真实执行时 I/O、锁、缓存等因素会让耗时差异很大
EXPLAIN 看到的每个字段都在反馈一个具体决策点。真正卡住性能的,往往不是“没索引”,而是“索引建了但没被用上”——而这需要你盯着 type、key_len、Extra 三处反复交叉验证。











