大数跨境
0
0

MySQL 如何优化 GROUP BY 和 ORDER BY?(收藏级指南)

MySQL 如何优化 GROUP BY 和 ORDER BY?(收藏级指南) Linux运维技术之路
2025-11-26
4
导读:MySQL 如何优化 GROUP BY 和 ORDER BY?

 










 

MySQL 如何优化 GROUP BY 和 ORDER BY?(收藏级指南)

在 SQL 优化中,GROUP BY 和 ORDER BY 是最容易导致性能“暴跌”的两个关键字
一旦使用不当,轻则创建临时表,重则出现 filesort、磁盘 I/O 暴增。

  • • 为什么 GROUP BY / ORDER BY 慢?
  • • 如何写索引让它们“飞起来”?
  • • 避免哪些坑?

一、为什么 GROUP BY / ORDER BY 很慢?

最本质的原因:

GROUP BY 和 ORDER BY 都需要排序(Sort)。
如果无法使用索引,就得用 filesort(排序算法)+ 临时表。

排序 + 临时表 = 直接慢成 PPT。

出现以下情况必慢:

1、无法使用索引排序
2、排序字段不连续(索引失效)
3、分组字段没有合适索引
4、排序字段与条件字段冲突
5、GROUP BY 使用隐式排序
6、使用 DISTINCT + ORDER BY 多字段排序
7、返回太多数据,临时文件写入磁盘

想优化,就是想办法:
尽可能让排序走索引减少排序量避免临时表


二、GROUP BY 的优化策略

1)给 GROUP BY 字段建索引(最有效)

示例:


   
    
   SELECT age, COUNT(*)
FROM
 user
GROUP
 BY age;

为 age 建索引:


   
    
   CREATE INDEX idx_user_age ON user(age);

MySQL 会利用索引的有序性,直接完成分组,而不需要额外排序。


2)WHERE 条件字段 + GROUP BY 字段做联合索引


   
    
   SELECT city, COUNT(*)
FROM
 user
WHERE
 status = 1
GROUP
 BY city;

此时应建:


   
    
   CREATE INDEX idx_status_city ON user(status, city);

原因:

  • • WHERE 过滤 first
  • • GROUP BY 分组 second

顺序必须和 SQL 一致,否则无效。


3)使用 GROUP BY 时关闭默认排序

MySQL 默认会对 GROUP BY 做排序。其实很多场景不需要。

可以加:


   
    
   GROUP BY city ORDER BY NULL;

减少一次排序,性能有显著提升。


4)避免 GROUP BY + ORDER BY 字段不一致


   
    
   GROUP BY city
ORDER
 BY age

那 MySQL 必须再排一次序 → 非常慢。
如果业务允许,将其统一为同一字段。


三、ORDER BY 的优化策略

1)最关键:ORDER BY 尽量使用索引排序

要使用索引排序必须满足:

排序字段必须是同一个索引中的最左前缀
并且
排序方向一致(全部 ASC 或全部 DESC)

示例:


   
    
   SELECT * 
FROM
 user 
ORDER
 BY age, id;

索引:


   
    
   CREATE INDEX idx_age_id ON user(age, id);

排序会直接利用 B+Tree 的顺序,无需 filesort。


2)WHERE 条件字段与 ORDER BY 字段冲突,可能导致排序失效

❌ 错误示例:


   
    
   WHERE city = 'beijing'
ORDER
 BY age

如果索引是:


   
    
   (city, age)

理论上应该能用索引排序,但如果 city 过滤后只剩很少数据,优化器可能判断“排序成本更低”,而不用索引 → filesort。

解决:

✔ 强制优化器使用索引(不推荐)
✔ or 更合理的方式:减少扫描量,如分页/索引覆盖


3)减少排序字段数量

避免多字段排序,尤其是 3 个以上字段。

⚠ 越多字段 → 越不可能用上索引。


4)避免 ORDER BY RAND()

这是性能灾难!

会导致:

  • • 生成随机值
  • • 对全表随机排序
  • • filesort 最慢模式

优化方法:使用主键随机 ID + limit


5)避免大数据量 ORDER BY,使用条件过滤 + 分页优化

比如:


   
    
   SELECT * FROM orders ORDER BY id LIMIT 100000, 20;

这会排序十万行,再丢掉 99980 行 → 极慢。

优化方法:


   
    
   SELECT * 
FROM
 orders 
WHERE
 id > 上一次最大ID
ORDER
 BY id 
LIMIT 20;

利用主键范围减少排序量 → 性能可提升百倍。


四、GROUP BY + ORDER BY 同时使用时(重灾区)

最常见 SQL:


   
    
   SELECT city, COUNT(*) 
FROM
 user
GROUP
 BY city
ORDER
 BY COUNT(*) DESC;

COUNT(*) 是动态生成值 → 无法走索引 → 必然 filesort

优化:

  • • 改成子查询(外层排序数据量小)

   
    
   SELECT * 
FROM
 (
    SELECT
 city, COUNT(*) AS cnt 
    FROM
 user
    GROUP
 BY city
) tmp
ORDER
 BY cnt DESC;

减少排序行数,通常可快 30%~90%。


五、总结:写 SQL 时必须记住的 8 条原则

1、 GROUP BY / ORDER BY 能走索引最优先
2、 索引顺序必须与 SQL 一致:WHERE → GROUP BY → ORDER BY
3、 GROUP BY 加 ORDER BY NULL(如果不需要排序)
4、ORDER BY 必须同向排序(都 ASC 或都 DESC)
5、多字段排序必须是最左前缀
6、避免 GROUP BY 和 ORDER BY 字段不一致
7、 大数据分页必须做分页优化(ID 范围筛选)
8、避免 filesort + 临时表(性能噩梦)

 




 

 


往期回顾

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