mysql中使用EXPLAIN分析查询语句的索引效率

来源:这里教程网 时间:2026-02-28 20:42:34 作者:

EXPLAIN 输出字段里哪些最关键

EXPLAIN
结果,别一上来就扫全列。重点关注这四个字段:
type
key
rows
Extra

type
值从好到差一般是:
const
eq_ref
>
ref
>
range
>
index
>
ALL
。出现
ALL
就是全表扫描,基本等于没走索引。

key
显示实际用到的索引名。如果为
NULL
,说明没走索引;如果和你预期的不一样,得查是否索引失效或优化器选错了。

rows
是 MySQL 预估需要扫描的行数,不是结果集行数。这个值越大,I/O 越高;比实际表行数还大,往往意味着索引没生效或条件写法有问题。

Extra
里要警惕:
Using filesort
(排序没走索引)、
Using temporary
(用了临时表)、
Using index condition
(ICP 开启,算好现象)、
Using where; Using index
(覆盖索引,理想状态)。

为什么加了索引却显示 type=ALL

常见原因不是索引没建,而是查询条件触发了索引失效。比如:

对索引字段做函数操作:
WHERE YEAR(create_time) = 2023
→ 改成
WHERE create_time >= '2023-01-01' AND create_time 
隐式类型转换:
WHERE user_id = '123'
(user_id 是 INT)→ 字符串强制转数字,索引失效
LIKE 以通配符开头:
WHERE name LIKE '%abc'
→ 无法用 B+ 树索引快速定位
联合索引没用最左前缀:
INDEX (a, b, c)
,但只查
WHERE b = 1 AND c = 2
→ 不走索引

检查时先用

SHOW CREATE TABLE
确认索引定义,再对照 WHERE 条件逐字核对是否满足最左匹配和无破坏性操作。

EXPLAIN FORMAT=JSON 能看出什么额外信息

默认的表格输出太简略。

EXPLAIN FORMAT=JSON
会返回嵌套结构,揭示优化器真实决策路径。重点关注:

used_key_parts
:实际用到的联合索引字段,比如
["a","b"]
表示只用了前两列
filtered
:表示该表条件过滤后剩余行数占比(百分比),值越低说明过滤效率越差
attached_condition
:下推到存储引擎层的条件,和
Using index condition
对应
rows_examined_per_scan
:单次扫描读取的行数,比普通
rows
更贴近真实 I/O

例如执行:

EXPLAIN FORMAT=JSON SELECT * FROM orders WHERE status = 'paid' AND amount > 100;

如果返回中

"used_key_parts": ["status"]
但没包含
amount
,说明联合索引可能缺了第二列,或者
amount
的范围查询截断了索引使用。

ORDER BY 和 GROUP BY 容易被忽略的索引细节

很多人只关注 WHERE 是否走索引,但排序和分组同样依赖索引结构。关键点:

ORDER BY a, b
要高效,索引必须是
(a, b)
或更长前缀,且方向一致(不能
ORDER BY a ASC, b DESC
INDEX (a ASC, b ASC)
GROUP BY
同理,如果没索引支持,就会触发
Using temporary; Using filesort
WHERE + ORDER BY
共存时,优先满足 WHERE 的最左前缀,再看能否覆盖 ORDER BY。比如
WHERE a = 1 ORDER BY b
,索引
(a, b)
就比
(b, a)
合适得多
注意 NULL 值处理:如果字段允许 NULL,而索引没特别设计,
ORDER BY col DESC
可能无法利用索引(因 NULL 默认排在最前,与 DESC 冲突)

一个典型陷阱:

SELECT * FROM logs WHERE app = 'web' ORDER BY id DESC LIMIT 20
。即使有
INDEX (app, id)
,若
id
是主键自增,MySQL 仍可能放弃该索引而走主键扫描——因为优化器认为按主键倒序取 20 行比用二级索引回表更便宜。这时得加
FORCE INDEX
或调整索引顺序验证。

相关推荐