MySQL 索引和 EXPLAIN 到底怎么学?(一次慢 SQL 优化复盘)h1
这次慢 SQL 是怎么发现的h2
当时是同一个列表接口,本地跑起来没感觉,到了测试环境数据量上来后直接变卡。
我最先犯的错是“先建索引再说”,结果加了两个索引耗时还是高。后来才老老实实按步骤排查:先看 SQL,再看执行计划,再决定索引。
这篇就是那次排查过程的原样记录。
我先把结论放前面h2
- 不要先建索引,先定位最慢 SQL
- 用
EXPLAIN看执行计划,不要靠感觉 - 联合索引要符合最左前缀原则
- 索引不是越多越好,写入也有成本
场景 SQLh2
SELECT id, user_id, status, amount, create_timeFROM ordersWHERE user_id = 10001 AND status = 1ORDER BY create_time DESCLIMIT 20;表结构(关键字段):
CREATE TABLE orders ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, status TINYINT NOT NULL, amount DECIMAL(10,2) NOT NULL, create_time DATETIME NOT NULL);第一步:先看执行计划h2
EXPLAIN SELECT ...;我重点看这几个字段:
type:访问类型,ALL最差,ref/range/const更好key:实际使用的索引rows:预估扫描行数Extra:有没有Using filesort、Using temporary
优化前(示意)h3
type: ALLkey: NULLrows: 600000Extra: Using where; Using filesort这说明几乎全表扫 + 文件排序,慢是必然。
第二步:设计索引h2
这个 SQL 的过滤条件是 user_id + status,排序字段是 create_time,所以我建了联合索引:
CREATE INDEX idx_user_status_ctimeON orders(user_id, status, create_time);为什么这样排顺序h3
- 先放过滤性较强且等值匹配字段
- 再放排序字段,尽量减少额外排序
第三步:再次 EXPLAINh2
优化后(示意)h3
type: refkey: idx_user_status_ctimerows: 200Extra: Using whererows 从 60 万降到几百,接口耗时明显下降。
我踩过的坑(很典型)h2
坑 1:在索引列上做函数运算h3
-- 不推荐WHERE DATE(create_time) = '2026-03-01'这样可能导致索引失效。改成范围查询更稳:
WHERE create_time >= '2026-03-01 00:00:00' AND create_time < '2026-03-02 00:00:00'坑 2:联合索引顺序写反h3
我一开始建的是 (status, user_id, create_time),实际业务里 user_id 过滤更强,应该放前面。
坑 3:盲目给每个字段都建索引h3
读性能可能会上去,但写入(insert/update)会变慢,还会增加存储成本。
这套顺序我后来一直在复用h2
- 抓到慢 SQL(日志 / 慢查询)
- 单独执行并记录耗时
EXPLAIN看type/key/rows/Extra- 针对 where + order by 设计索引
- 再次
EXPLAIN+ 回归测试
面试里我会这样讲h2
可以按这个结构讲:
- 问题:订单列表在大数据量下响应慢
- 分析:
EXPLAIN显示全表扫描 + 文件排序 - 方案:新增联合索引
(user_id, status, create_time) - 结果:扫描行数显著下降,接口耗时下降
重点不是“我背过索引知识点”,而是“我能把问题定位到 SQL,再用数据验证优化有没有生效”。
评论