group by慢的主因是未走索引触发using temporary和using filesort;需建最左前缀联合索引(where等值字段前置+group by字段居中),确保select非聚合列在索引左侧,避免select *、having过滤及隐式排序。

先看执行计划里有没有 Using temporary 或 Using filesort —— 有,就是病根;没有,再往下查。
怎么一眼看出 GROUP BY 是否触发了临时表
直接跑 EXPLAIN FORMAT=TRADITIONAL,重点盯 Extra 列:
-
Using temporary:说明 MySQL 把所有匹配行拉进内存或磁盘临时表,再分组——这是最典型的性能断崖信号 -
Using filesort:哪怕 GROUP BY 字段有索引,但排序逻辑无法复用索引顺序(比如后面跟了ORDER BY COUNT(*) DESC),也会强制排序 -
key显示用了索引,但Extra还有上面两个词,等于索引“白挂了”,没帮上分组的忙 -
type是ALL或index(不是ref/range),基本说明 WHERE 条件根本没走索引,GROUP BY 更无从谈起
为什么加了索引还是慢
常见错觉:给 GROUP BY 字段单独建了索引,就以为万事大吉。其实失效场景很具体:
- 索引顺序不对:
GROUP BY a, b,但索引是(b, a)或(a)单列——B+ 树不支持跳过前缀直接按后缀分组 - SELECT 字段没覆盖:
SELECT a, b, SUM(c) FROM t GROUP BY a, b,索引只建了(a, b),c得回表查,IO 暴增 - WHERE 条件破坏最左前缀:
WHERE status = 1 AND created_at > '2024-01-01',但索引是(user_id, status, created_at)——user_id没在 WHERE 里,前面两列全废 - 隐式类型转换:
WHERE user_id = '123'(字段是BIGINT)——索引失效,覆盖自然崩
什么情况下 DISTINCT 能秒杀 GROUP BY
当查询目标只是“列出所有满足条件的组合”,并不需要聚合值(比如 COUNT(*)、SUM()),DISTINCT 常常快一个数量级:
-
SELECT DISTINCT customer_id, city FROM orders WHERE ...vsSELECT customer_id, city FROM orders WHERE ... GROUP BY customer_id, city - SQL Server 和 MySQL 都对
DISTINCT更倾向用Sort + Unique,而GROUP BY可能触发哈希聚合或临时表 - 注意语义:如果后续要加
HAVING或聚合函数,就不能简单替换 - 别被“语法等价”骗了——执行引擎底层路径完全不同
建索引时最容易忽略的顺序细节
联合索引不是字段堆砌,顺序决定它能不能真正加速 GROUP BY:
- 必须按
WHERE → GROUP BY → SELECT字段顺序排列 - 范围条件(如
created_at > '2024-01-01')要放 WHERE 中高区分度字段之后,不能放最右——否则后续字段无法走索引 - 示例:
WHERE status IN ('A','B') AND created_at > '2024-01-01' GROUP BY user_id, product_type,最优索引是(status, created_at, user_id, product_type) - 如果还要
SELECT MAX(amount),就把amount加到末尾做INCLUDE(SQL Server)或普通索引列(MySQL),形成覆盖
真正卡住 GROUP BY 的,往往不是数据量本身,而是索引没对上执行路径——EXPLAIN 里的 Extra 是唯一可信线索,其他都是猜测。











