作为一名后端开发者,你是否遇到过这样的场景:系统上线初期一切正常,随着数据量增长,某些查询越来越慢,最终拖垮整个服务?大多数情况下,罪魁祸首就是索引问题。
今天,我们来聊聊 MySQL 索引优化的那些实战技巧,帮你从根本上解决慢查询问题。

一、先搞清楚:索引是什么?
索引本质上是一种数据结构(MySQL InnoDB 默认使用 B+ 树),它通过额外的存储空间换取查询速度。就像书的目录,让你不必翻遍全书就能找到目标内容。
但索引不是越多越好——每次写入(INSERT/UPDATE/DELETE)都需要同步维护索引,索引过多会拖慢写操作,还会占用大量磁盘空间。
二、EXPLAIN 是你最好的朋友
优化索引的第一步,是学会读懂 EXPLAIN 输出:
EXPLAIN SELECT * FROM orders WHERE user_id = 1001 AND status = 'paid';
重点关注这几列:
- type:访问类型,从好到差依次是
const→ref→range→index→ALL。出现ALL说明全表扫描,必须优化。 - key:实际使用的索引,为 NULL 说明没走索引。
- rows:预估扫描行数,越小越好。
- Extra:出现
Using filesort或Using temporary是性能警报。
三、联合索引的最左前缀原则
这是最容易踩坑的地方。假设有联合索引 (a, b, c):
-- ✅ 走索引
SELECT * FROM t WHERE a = 1;
SELECT * FROM t WHERE a = 1 AND b = 2;
SELECT * FROM t WHERE a = 1 AND b = 2 AND c = 3;
-- ❌ 不走索引(跳过了 a)
SELECT * FROM t WHERE b = 2;
SELECT * FROM t WHERE c = 3;
-- ⚠️ 部分走索引(a 走索引,c 不走)
SELECT * FROM t WHERE a = 1 AND c = 3;
建联合索引时,把区分度高、查询频率高的列放在前面。
四、索引失效的常见场景
很多开发者建了索引,却发现查询还是很慢,原因往往是索引失效了:
1. 对索引列做函数运算
-- ❌ 索引失效
SELECT * FROM users WHERE YEAR(create_time) = 2025;
-- ✅ 改写为范围查询
SELECT * FROM users WHERE create_time BETWEEN '2025-01-01' AND '2025-12-31';
2. 隐式类型转换
-- phone 字段是 varchar,传入数字会导致索引失效
-- ❌
SELECT * FROM users WHERE phone = 13800138000;
-- ✅
SELECT * FROM users WHERE phone = '13800138000';
3. LIKE 以通配符开头
-- ❌ 索引失效
SELECT * FROM products WHERE name LIKE '%手机';
-- ✅ 前缀匹配可以走索引
SELECT * FROM products WHERE name LIKE '苹果%';
4. OR 条件中有非索引列
-- 如果 age 没有索引,整个查询都不走索引
SELECT * FROM users WHERE id = 1 OR age = 25;
五、覆盖索引:减少回表的利器
当查询的所有字段都在索引中时,MySQL 不需要回表查主键索引,这就是覆盖索引,性能提升非常显著。
-- 假设有索引 (user_id, status, amount)
-- 以下查询可以直接从索引获取数据,无需回表
SELECT user_id, status, amount FROM orders WHERE user_id = 1001;
在 EXPLAIN 的 Extra 列看到 Using index,说明用上了覆盖索引,是个好信号。
六、实战:一次慢查询优化过程
以订单表为例,原始查询:
SELECT order_no, amount, status, create_time
FROM orders
WHERE user_id = 1001 AND status = 'paid'
ORDER BY create_time DESC
LIMIT 10;
优化步骤:
- EXPLAIN 发现 type=ALL,全表扫描,rows=500万
- 分析查询条件:等值查询 user_id、status,排序 create_time
- 建立联合索引:
ALTER TABLE orders ADD INDEX idx_user_status_time (user_id, status, create_time); - 再次 EXPLAIN:type=ref,rows=12,Extra=Using index
- 查询时间从 3.2s 降至 0.003s,提升超过 1000 倍
七、索引优化的几条原则
- 🎯 按需建索引:只为高频查询的 WHERE、JOIN、ORDER BY 字段建索引
- 📊 关注区分度:性别这种区分度极低的字段不适合单独建索引
- 🔍 定期审查:用
SELECT * FROM sys.schema_unused_indexes找出从未使用的索引并删除 - ⚖️ 读写平衡:写多读少的表要控制索引数量,避免写性能下降
- 📏 前缀索引:对长字符串字段,可以只索引前 N 个字符节省空间
结语
索引优化没有银弹,需要结合具体的业务场景、数据分布和查询模式来分析。养成用 EXPLAIN 分析慢查询的习惯,理解最左前缀原则和索引失效场景,大多数性能问题都能迎刃而解。
记住:过早优化是万恶之源,但对于数据库索引,提前规划总比事后救火要好得多。
觉得有用就点个赞吧~