GROUP BY 不只是“分组统计语法”,它本质上是把输入行按分组键归并,并维护每个分组的聚合状态。访问路径合适时,相同分组可以按索引顺序连续出现;路径不合适时,就需要内部临时表保存中间结果。
所以 GROUP BY 的成本通常不在语法本身,而在输入行规模、分组键顺序、临时表是否落盘,以及聚合状态如何维护。
先把机制边界说清楚
GROUP BY 的本质是把输入行按分组键归并,并为每个分组维护聚合结果。它可以利用索引顺序让相同分组连续出现,也可以用内部临时表保存分组状态。前者更像顺序扫描,后者更像边读边构建一张中间结果表。
整体路径
上面这张图先看粗线条:宏观上,GROUP BY 的链路从过滤候选行开始,然后判断分组键是否与索引顺序匹配。匹配时可以走紧凑索引扫描或松散索引扫描;不匹配时就要建立临时表,按分组键查找或插入聚合行,最后再按需要排序、过滤 having 或返回。
底层流程
底层拆解先看数据结构。「GROUP BY」至少涉及下面几类结构:
- 分组键:决定哪些输入行归为同一个聚合桶。
- 聚合状态:保存 count、sum、min、max 等中间结果。
- 内部临时表:索引顺序不能直接满足分组时,用来承载中间聚合结果。
- 松散索引扫描:在特定 min/max 和前缀条件下跳过无关索引项。
再看完整执行流程:
- 先根据 where 条件确定候选输入行。
- 优化器判断 group by 是否可利用索引顺序。
- 可利用时按索引顺序连续读取同组数据并更新聚合状态。
- 不可利用时写入内部临时表,按分组键查找或新增聚合行。
- 处理 having、order by 和 limit 后返回结果。
取舍与边界
版本差异上,MySQL 8.4 文档明确说明,GROUP BY 不再像 8.3 及更早版本那样在某些条件下隐式排序。业务如果需要稳定顺序,必须显式 ORDER BY。8.0 之后内部临时表引擎和优化器能力持续增强,但分组是否能吃到索引顺序,仍然取决于查询形态和索引设计。
GROUP BY 的短板是中间状态容易失控。分组基数很高时,临时表会快速膨胀;聚合列很宽时,内存压力会上升;where 过滤不充分时,MySQL 会为了少量分组结果扫描大量原始行。
典型问题:用机制化例子排查
分组统计的成本通常来自中间状态:输入行有多少、分组键能不能复用索引顺序、临时表会不会落盘。语法简单,不代表执行便宜。
可以落到这些动作:
- 分组键尽量和 where 前缀、索引顺序对齐。
- 避免在分组列上做函数包裹,必要时用冗余字段或生成列承载分组维度。
- 高频看板不要直接扫交易明细,使用实时增量汇总或离线宽表。
- 看到 Using temporary 时,结合分组基数和临时表落盘指标判断风险。
收束:分组是中间状态管理
GROUP BY 的核心不是语法,而是中间状态管理。能用索引顺序完成的分组,是查询优化;需要临时表兜底的分组,就是资源治理问题。
关于十三Tech
我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。
我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。
如果你想继续跟完这套「图解 MySQL」,欢迎关注公众号 「十三Tech」。后续会继续按机制、图解和实战排查这条线更新。

