Skip to content
MySQL 存储引擎与执行细节 · 第 4 篇 / 共 4 篇
领域数据与中间件
专题MySQL 专题
当前序列MySQL 存储引擎与执行细节
阅读位置第 4 篇 / 共 4 篇当前专题第 3 个序列 / 共 7 个序列

ORDER BY、GROUP BY 为什么容易慢

先说结论

  • ORDER BYGROUP BY 慢,很多时候不是 SQL 写错,而是没走上合适索引
  • 一旦需要额外排序、临时表或大范围扫描,成本就会明显上来
  • 真正排查时,先看扫描范围,再看排序和分组能不能在索引层解决

一、为什么这两类操作天然更重

因为它们都不是“取出数据就结束”。

  • ORDER BY 需要确定顺序
  • GROUP BY 需要聚合归并

如果数据库不能直接沿着索引顺序把结果吐出来,就通常要额外做:

  • 排序
  • 建临时表
  • 聚合中间结果

这也是为什么很多查询条件不算复杂,但一加排序或分组就明显变慢。

二、ORDER BY 最常慢在哪

1. 排序列没命中索引顺序

如果 where 条件和 order by 的列组合与索引不匹配,数据库往往只能先筛再排,代价会很高。

2. 返回行数太多

哪怕排序逻辑没问题,结果集本身很大时,排序成本也会明显上升。

3. 排序方向和索引顺序不匹配

有些场景即使有索引,也未必能完全利用。

三、GROUP BY 最常慢在哪

1. 先扫很多,再聚合

如果过滤条件不够收敛,分组前就已经读了太多数据,后面的聚合自然会重。

2. 分组字段基数高

分组值越分散,中间结果通常越大,内存和临时表压力也越明显。

3. 还叠加排序

很多 SQL 不只是 GROUP BY,还会再加:

  • ORDER BY count(*) desc
  • LIMIT

这类语句很容易把“聚合 + 排序”两个重操作叠起来。

四、排查时优先看什么

更实用的顺序通常是:

  1. 先看 where 条件是否已经收住扫描范围。
  2. 再看排序或分组字段是否有合适索引支持。
  3. 再看是不是出现了临时表、文件排序之类的额外成本。
  4. 最后再决定是改 SQL、补索引,还是改查询思路。

很多时候不是数据库扛不住,而是让它做了本来就不适合在线实时做的大排序和大聚合。

五、最容易踩的坑

1. 以为有索引就一定不会排序

索引有没有建,和能不能按当前条件、当前顺序真正用上,是两回事。

2. 先把结果全查出来再排序分页

这类写法在数据一多时,性能会很快变差。

3. 把统计类 GROUP BY 直接压在主库热点表上

如果是高频看板、报表类需求,很多时候更适合走汇总表、缓存或离线链路。

总结

ORDER BYGROUP BY 容易慢,不是因为它们“特殊”,而是因为一旦索引不匹配,就会触发额外排序、聚合和临时表开销。排查时先看扫描范围,再看索引能不能承接排序和分组,比上来就调参数更有效。

延伸阅读相关文章优先当前专题,再补跨专题关联。
同一序列 · 回看前文会更完整覆盖索引和最左前缀原则怎么真正用起来适合把 MVCC、索引、排序聚合和日志系统放在一起深入看。MySQL 专题 · MySQL 存储引擎与执行细节同一序列 · 回看前文会更完整隔离级别和幻读问题怎么放到 InnoDB 里看适合把 MVCC、索引、排序聚合和日志系统放在一起深入看。MySQL 专题 · MySQL 存储引擎与执行细节同专题其他序列 · MySQL 变更与运维治理大表在线 DDL 怎么做更稳适合把计数、日志、在线变更和归档清理放在一起看。MySQL 专题 · MySQL 变更与运维治理同专题其他序列 · MySQL 变更治理与数据生命周期大事务为什么会拖垮数据库适合把大事务、DDL、回填、慢 SQL 治理和归档分层放进一条持续治理主线上看。MySQL 专题 · MySQL 变更治理与数据生命周期跨专题关联 · 同场景:基础学习@Conditional 系列注解怎么配合使用适合把自动装配、条件装配、Profile 和循环依赖放回 Spring Boot 启动过程里理解。Spring 专题 · Spring Boot 启动、装配与配置跨专题关联 · 同场景:基础学习保留策略和日志压缩适合哪些场景适合把副本机制、acks、批量压缩和日志组织放在一条 Kafka 投递主线上理解。Kafka 专题 · Kafka 投递链路与日志存储机制
继续阅读MySQL 存储引擎与执行细节当前序列第 4 篇 / 共 4 篇当前专题第 3 个序列 / 共 7 个序列
往前看
上一篇覆盖索引和最左前缀原则怎么真正用起来回到当前序列上一章上一序列MySQL 事务、锁与高可用从第 1 篇开始:MySQL 事务与锁
往后看
下一序列MySQL 变更与运维治理从第 1 篇开始:COUNT(*) 和 COUNT(列) 到底差在哪

把零散经验整理成可查、可复用、可持续更新的企业级知识门户