EXPLAIN 是查看 MySQL 索引使用情况最直接的方法,需关注 key(非 NULL 表示用索引)、type(const/ref/range 为走索引,ALL 为全表扫描)、rows(远小于总行数说明过滤有效)、Extra(出现 Using filesort 或 temporary 表示额外开销)。
EXPLAIN 看执行计划是最直接的方法MySQL 不会主动告诉你“用了哪个索引”,但 EXPLAIN 会把优化器的决策摊开给你看。在 SQL 前加 EXPLAIN,重点关注 type、key、rows、Extra 这几列:
key 列非 NULL(比如显示 idx_user_id)→ 实际使用了该索引type 是 const / ref / range → 通常走索引;如果是 ALL → 全表扫描,没走索引rows 值远小于表总行数 → 说明索引过滤有效;接近总数则可能失效Extra 出现 Using filesort 或 Using temporary → 即使走了索引,排序/分组仍可能回表或额外开销注意:仅 key 非空不等于“高效”,还要结合 type 和 rows 综合判断。
索引存在 ≠ 被使用。常见隐形失效场景包括:
WHERE YEAR(create_time) = 2025 → create_time 上的索引失效WHERE user_id = '123'(user_id 是 INT)→ 可能放弃索引!= 或 NOT IN(尤其右侧含 NULL)→ 优化器常弃用索引LIKE 以通配符开头:LIKE '%abc' → 无法利用 B+ 树前缀匹配特性INDEX (a, b, c),只查 WHERE b = 1 → 不走索引这些不是语法错误,SQL 能正常执行,但执行计划里 key 会是 NULL,type 变成 ALL。
FORCE INDEX 能强制走索引,但要小心当优化器误判(比如统计信息过期、小表误选全表扫描),可用 FORCE INDEX 干预:
SELECT * FROM orders FORCE INDEX(idx_status_created) WHERE status = 'paid' AND created_at > '2025-01-01';
但它不解决根本问题:
FORCE INDEX 可能从“救急”变“拖累”USE INDEX 更温和,IGNORE INDEX 有时比硬刚更有用上线前务必用真实数据量 + EXPLAIN FORMAT=JSON 验证效果,别只看开发环境。
简化版 MySQL 执行流程:连接 → 解析 → 优化(生成执行计划)→ 执行 → 返回。索引参与的是「优化」和「执行」两步:
SHOW INDEX FROM tbl + INFORMATION_SCHEMA.STATISTICS)、成本模型,决定是否用索引、用哪个、是否下推条件(ICP)所以,ANALYZE TABLE 更新统计信息、避免长期不 OPTIMIZE 导致页分裂严重,都是影响“是否走索引”的底层因素——它们不改变 SQL 写法,但会改变优化器的选择。