大数跨境
0
0

MySQL 如何选择合适的索引?

MySQL 如何选择合适的索引? Linux运维技术之路
2025-11-20
4
导读:MySQL 如何选择合适的索引?

 










 

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 组合成联合索引)。


④ 高频查询但字段区分度高

索引的效果与字段的“区分度”密切相关。

区分度 = 该字段不同值的数量 / 总行数

例如:

字段
区分度
适合做索引?
id
很高
✔✔✔
phone
很高
✔✔✔
email
很高
✔✔✔
gender
极低
❌(索引意义不大)

区分度低的字段,即使建索引,优化器也可能放弃使用。


⑤ 经常被查询,但字段较小

索引会占用存储空间,字段越长,索引越大,维护成本越高。

因此:

  • • 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、不适合建索引的情况包括:小表、低区分度字段、频繁更新的字段、大字段等。

 




 

 


往期回顾


【声明】内容源于网络
0
0
Linux运维技术之路
专注运维架构、高可用、高并发、高性能、大数据、容器化、数据库、python、devops等开源技术和实践的分享。
内容 347
粉丝 0
Linux运维技术之路 专注运维架构、高可用、高并发、高性能、大数据、容器化、数据库、python、devops等开源技术和实践的分享。
总阅读675
粉丝0
内容347