SQL GROUP BY性能瓶颈集中在数据扫描、分组定位和聚合计算三环节:无索引导致全表扫描;隐式排序触发临时表与文件排序;分组键分散或聚合复杂加剧CPU与内存压力。

SQL GROUP BY 的性能瓶颈主要集中在三个环节:数据扫描、分组定位和聚合计算。它不是单纯“慢”,而是每个环节都可能被放大——尤其当数据量上升、索引缺失或写法不当的时候。
全表扫描导致 I/O 和 CPU 暴涨
如果 GROUP BY 字段没有索引,或者索引未被有效利用(比如用了函数、顺序不匹配),数据库只能逐行读取整张表。type=ALL 的 EXPLAIN 结果就是典型信号。百万级表全扫一遍,光磁盘读取就耗掉大半时间。
- 常见诱因:GROUP BY YEAR(create_time)、GROUP BY UPPER(name)、索引字段顺序与 GROUP BY 不一致
- 后果:不仅慢,还容易触发并发争抢、锁等待,拖垮整个连接池
临时表和文件排序吃光内存
MySQL 默认会对 GROUP BY 字段隐式排序,若无法利用索引顺序完成分组,就会创建临时表(Using temporary),并可能落盘排序(Using filesort)。一旦 tmp_table_size 或 sort_buffer_size 不足,就会写磁盘,I/O 成为最大瓶颈。
- EXPLAIN 中看到 Using temporary 或 Using filesort 就该警觉
- 大字段参与分组(如 GROUP BY content)会极大增加临时表体积,极易溢出
分组桶数过多或聚合逻辑过重
分组键越分散、值越多,需要维护的“桶”就越多;聚合函数越复杂(尤其是 DISTINCT、子查询嵌套、JSON 处理),CPU 开销就越大。例如 COUNT(DISTINCT user_id) 在千万级数据上常需哈希+排序双阶段,内存压力陡增。
- 字符串拼接分组(如 GROUP BY CONCAT(a,b))既无法走索引,又加重 CPU 和内存负担
- SELECT 中带 TEXT/JSON 字段,即使没用于分组,也可能被拉入临时表参与排序
隐式排序带来无谓开销
在 MySQL 8.0 之前,GROUP BY 总是附带排序行为,哪怕你根本不需要结果有序。这多出来的 O(n log n) 排序成本,在数据量大时非常可观。
- 解决办法很简单:显式加上 ORDER BY NULL,告诉优化器跳过排序
- MySQL 8.0+ 支持松散索引扫描(Loose Index Scan),但前提是索引顺序完全匹配且无 WHERE 干扰











