- Published on
MySQL 索引优化实战:从原理到 EXPLAIN
- Authors

- Name
- Allen Wang
MySQL 索引优化实战:从原理到 EXPLAIN
索引不是“建了就快”,而是“建对了才快”。
这篇文章给你一个新手也能落地的路径:
- 先理解索引为什么快
- 再掌握哪些 SQL 能吃上索引
- 最后用 EXPLAIN 验证优化是否有效
目录
- 1 - 索引为什么快
- 2 - B+Tree 索引核心机制
- 3 - 最左前缀与复合索引
- 4 - 回表、覆盖索引与索引下推
- 5 - EXPLAIN 实战判读
- 6 - 常见索引失效场景
- 7 - 交互式可视化
- 8 - 可执行优化清单
1 - 索引为什么快
没有索引时,MySQL 往往只能全表扫描:
SQL
SELECT id, username FROM users WHERE username = 'john';
如果 username 没有索引,优化器可能读取大量无关行。
有索引时:
SQL
CREATE INDEX idx_users_username ON users(username);
优化器可通过索引快速定位目标记录,再按需回表。
2 - B+Tree 索引核心机制
MySQL InnoDB 默认使用 B+Tree 索引(常口语称 B-Tree)。
关键点:
- 非叶子节点:仅存键与子指针
- 叶子节点:存键值与记录定位信息
- 叶子链表:支持范围查询与排序扫描
所以这类查询通常很友好:
- 等值:
= - 范围:
>,<,BETWEEN - 排序:
ORDER BY(与索引顺序一致时)
3 - 最左前缀与复合索引
给定复合索引:
SQL
CREATE INDEX idx_user_status_time ON orders(user_id, status, created_at);
可高效利用的常见写法:
SQL
-- 命中 (user_id)
SELECT * FROM orders WHERE user_id = 1001;
-- 命中 (user_id, status)
SELECT * FROM orders WHERE user_id = 1001 AND status = 'paid';
-- 命中 (user_id, status, created_at)
SELECT * FROM orders
WHERE user_id = 1001 AND status = 'paid' AND created_at >= '2025-01-01';
容易失效的写法:
SQL
-- 跳过了最左列 user_id,通常无法高效命中该复合索引
SELECT * FROM orders WHERE status = 'paid';
4 - 回表、覆盖索引与索引下推
4.1 回表
如果二级索引不包含查询所需列,MySQL 需要先查索引再回主键索引取完整行。
4.2 覆盖索引
当查询列都在同一个索引内,可避免回表:
SQL
CREATE INDEX idx_users_name_age ON users(name, age);
SELECT age FROM users WHERE name = 'John';
4.3 索引下推(ICP)
对部分范围条件,MySQL 可在索引层提前过滤,减少回表次数。
5 - EXPLAIN 实战判读
SQL
EXPLAIN SELECT age FROM users WHERE name = 'John';
重点看:
type:访问方式(const/ref/range通常优于ALL)key:实际使用的索引rows:预估扫描行数Extra:如Using index(覆盖索引)、Using filesort(额外排序)
一个实用目标:
type从ALL变为ref/rangerows显著下降Extra去掉Using filesort/Using temporary(若可行)
6 - 常见索引失效场景
- 对索引列做函数操作
SQL
-- 可能失效
SELECT * FROM users WHERE DATE(created_at) = '2025-01-01';
-- 改写为范围,通常可命中
SELECT * FROM users
WHERE created_at >= '2025-01-01' AND created_at < '2025-01-02';
- 隐式类型转换
SQL
-- phone 是 varchar,传 int 可能导致转换
SELECT * FROM users WHERE phone = 13800138000;
- 前导通配符
SQL
-- '%abc' 一般无法利用普通 B+Tree 前缀能力
SELECT * FROM docs WHERE title LIKE '%mysql';
7 - 交互式可视化
8 - 可执行优化清单
- 核心慢 SQL 是否已抓取(慢查询日志 / APM)
- 是否先
EXPLAIN再改索引 - 复合索引列顺序是否按过滤选择性与查询模式设计
- 是否确认“读提升”与“写放大”之间的权衡
- 是否定期清理无用/重复索引
如果你刚开始做性能优化,建议先从“Top 5 慢 SQL + EXPLAIN 对比”入手,收益通常非常直接。