绝大多数慢查询源于WHERE字段未建索引,导致全表扫描;应通过EXPLAIN检查type是否为ALL,合理创建复合索引并注意字段顺序,避免对索引字段使用函数。

WHERE 条件字段没加索引,查询直接变慢十倍
绝大多数慢查询的根源,就是 WHERE 子句里用到的字段没建索引。数据库没法跳过扫描,只能全表逐行比对。
实操建议:
- 用
EXPLAIN看执行计划,重点关注type列:如果是ALL,基本等于全表扫描 - 复合索引要注意字段顺序——
WHERE a = ? AND b = ?适合建(a, b),但WHERE b = ?单独用就用不上这个索引 - 避免在索引字段上做函数操作,比如
WHERE YEAR(created_at) = 2023会让created_at索引失效;改用WHERE created_at >= '2023-01-01' AND created_at
SELECT * 会拖慢带索引的查询
即使 WHERE 字段有索引,如果查的是 SELECT *,且表里有大字段(如 TEXT、BLOB),数据库仍可能放弃走索引,转而用主键回表取数据,IO 成倍增加。
实操建议:
- 只查真正需要的列,尤其是避免在高频查询中返回大字段
- 如果经常按某几个字段查询,考虑建覆盖索引:比如常查
SELECT user_id, name, email FROM users WHERE status = ?,可建(status, user_id, name, email) - 注意覆盖索引的大小——字段越多、越宽,索引体积越大,写入和维护成本越高
ORDER BY 和 LIMIT 配合索引失效的典型场景
ORDER BY 不走索引最常见于两种情况:排序字段没索引,或排序字段和 WHERE 字段不在同一个索引里。
实操建议:
-
WHERE a = ? ORDER BY b要想走索引,得建联合索引(a, b),而不是分开建两个单列索引 -
ORDER BY b DESC和WHERE a = ?混用时,(a, b DESC)在 MySQL 8.0+ 才被原生支持;老版本建(a, b)后,DESC可能无法利用索引排序 -
LIMIT很小但偏移量很大(如LIMIT 10000, 20)时,即使有索引,数据库仍要先定位前 10000 行——这时更适合用游标分页(基于上一页最后 ID 继续查)
索引不是越多越好,UPDATE/INSERT 会明显变慢
每多一个索引,写操作就要多维护一份 B+ 树结构。尤其在高并发写入场景下,索引数量和大小直接影响性能瓶颈位置。
实操建议:
- 删掉长期没被
WHERE、JOIN、ORDER BY用到的索引,用information_schema.statistics或云厂商的索引使用率监控辅助判断 - 区分冷热数据:对归档表或低频更新表可适当多建索引;对日志类高频写入表,优先保写入吞吐,少建甚至不建非必要索引
- 字符串字段建索引要谨慎——
VARCHAR(500)全长建索引开销大,可考虑前缀索引:INDEX (title(100)),但需验证前缀是否真能区分大部分值
索引优化从来不是“建了就快”,而是权衡读写、匹配查询模式、持续观察执行计划的过程。最容易被忽略的,是上线后没人再看 EXPLAIN——等慢查询报警才查,往往已经积压了多个失效索引。


















