用 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) = 2023→
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 > '2024-01-01';
但它不解决根本问题:
如果索引本身设计不合理(比如缺失覆盖字段),强制后反而更慢 后续数据分布变化后,FORCE INDEX可能从“救急”变“拖累” MySQL 8.0+ 中,
USE INDEX更温和,
IGNORE INDEX有时比硬刚更有用
上线前务必用真实数据量 +
EXPLAIN FORMAT=JSON验证效果,别只看开发环境。
执行流程中索引在哪一步介入
简化版 MySQL 执行流程:连接 → 解析 → 优化(生成执行计划)→ 执行 → 返回。索引参与的是「优化」和「执行」两步:
优化阶段:优化器基于统计信息(SHOW INDEX FROM tbl+
INFORMATION_SCHEMA.STATISTICS)、成本模型,决定是否用索引、用哪个、是否下推条件(ICP) 执行阶段:存储引擎(如 InnoDB)按执行计划调用索引 B+ 树查找,定位到主键或数据页,再回表(若非覆盖索引)
所以,
ANALYZE TABLE更新统计信息、避免长期不
OPTIMIZE导致页分裂严重,都是影响“是否走索引”的底层因素——它们不改变 SQL 写法,但会改变优化器的选择。
