MySQL 如何选择合适的索引?
“SQL 慢?先看索引!”
但真正的问题是:
👉 索引到底应该怎么选?
👉 选择什么字段?单列还是联合?顺序怎么排?
👉 建少了不够用,建多了影响写入,怎么办?
一、什么字段适合建立索引?
以下 5 类字段最适合建立索引:
① 出现在 WHERE 条件中的字段
这是最基本、也是最重要的原则。
比如查询:
SELECT * FROM user WHERE phone = '13888888888';
显然 phone 就非常适合做索引。
② 出现在 JOIN 条件中的字段
JOIN 用来关联表,因此关联字段必须建立索引,否则两张大表就会产生超高成本的嵌套循环。
例如:
SELECT * FROM orders o JOIN user u ON o.user_id = u.id;
索引必须建在 orders.user_id 上。
③ 出现在 ORDER BY / GROUP BY 的字段
如果没有索引:
-
• ORDER BY 会产生 Using filesort -
• GROUP BY 可能产生 Using temporary
两者都是性能杀手。
所以:
ORDER BY create_time
GROUP BY status
都应该建索引(最好与 where 组合成联合索引)。
④ 高频查询但字段区分度高
索引的效果与字段的“区分度”密切相关。
区分度 = 该字段不同值的数量 / 总行数
例如:
区分度低的字段,即使建索引,优化器也可能放弃使用。
⑤ 经常被查询,但字段较小
索引会占用存储空间,字段越长,索引越大,维护成本越高。
因此:
-
• VARCHAR(2000) 不适合做索引 -
• 可以考虑前缀索引
例如:
CREATE INDEX idx_email ON user(email(10));
二、什么时候不要建索引?
以下情况一般不适合建索引:
❌ 低区分度字段
如 gender、status(只有 0/1)、type(1~5)
❌ 小表(例如几百行)
建索引反而可能更慢,全表扫描更快。
❌ 经常更新的字段(特别是频繁写入的大表)
索引会增加写入成本,插入或更新时需要维护 B+ 树结构。
例如:
update_time、pv_count、stock
一般不建议建立索引。
三、单列索引 vs 联合索引,应该怎么选?
核心金句:
能建立联合索引就不要建多个单列索引。
因为多个单列索引不能共同加速一个查询。
例如 SQL:
WHERE name = 'Tom' AND age = 20
即使 name 和 age 都有单列索引,优化器依然只能使用一个。
正确做法是:
INDEX(name, age)
四、联合索引字段顺序怎么排?(最左前缀原则)
排序原则如下:
✔ 原则 1:把区分度高的字段放在最左边
例如:
性别(区分度低)
城市(中)
手机号(区分度非常高)
那么索引顺序应该是:
(phone, city, gender)
✔ 原则 2:与 WHERE 条件匹配顺序一致
例如:
WHERE user_id = ? AND status = ? AND create_time > ?
那么索引最好是:
(user_id, status, create_time)
✔ 原则 3:等值放前面,范围放后面
非常关键!
例如:
WHERE name = ? AND age > ?
索引应该是:
(name, age)
因为:
-
• 等值(=)可以继续使用后续字段索引 -
• 范围(> < between)后面的字段将无法使用
五、避免回表:尽量做成覆盖索引
覆盖索引能够让 MySQL 不回表,速度非常快。
例如查询:
SELECT name, age FROM user WHERE name = 'Tom';
可以建立:
INDEX(name, age)
这样所有字段都在索引树里,不需要回表。
EXPLAIN 会显示:
Extra: Using index
这是最优情况。
六、最佳实践:如何为一条 SQL 选择索引?
以 SQL 为中心,逆向推导索引。
给你一条 SQL 示例:
SELECT user_id, price
FROM orders
WHERE user_id = 1001 AND status = 1
ORDER BY create_time DESC
LIMIT 10;
索引应该是什么?
👉 这是典型的:
-
• 等值(user_id) -
• 等值(status) -
• 排序(create_time)
最佳索引:
INDEX(user_id, status, create_time)
并且是 符合最左前缀原则的完美联合索引。
总结
1、MySQL 索引应该选择出现在 WHERE、JOIN、ORDER BY、GROUP BY 中的字段,优先使用区分度高、字段较小、查询频繁的字段。
2、在多条件查询中,应优先使用联合索引而不是多个单列索引,并根据等值优先、范围其次、区分度高在前的原则安排字段顺序。
3、查询字段尽量覆盖索引以减少回表。
4、不适合建索引的情况包括:小表、低区分度字段、频繁更新的字段、大字段等。

