GROUP BY 查询慢主因是未走索引,出现Using temporary或Using filesort即索引失效;需按WHERE等值条件→GROUP BY字段顺序建联合索引,并避免函数、模糊查询等导致索引失效的操作。

GROUP BY 查询慢,八成是因为没走索引,而不是数据量大。 一旦执行计划里出现 Using temporary 或 Using filesort,基本可以断定索引没用上——这时候加索引比调参数、换硬件更直接有效。
为什么 GROUP BY 必须靠索引“有序性”才能快
MySQL 的 GROUP BY 不是边扫边分组,而是依赖索引的物理顺序来自然归并:如果索引叶子节点已经是按 dept 排好序的,那扫描时遇到相同 dept 就自动聚成一组,无需建临时表、也不用额外排序。
- 没有索引 → 全表扫描 + 内存/磁盘临时表 + 排序 →
Using temporary; Using filesort - 有单列索引
(dept)→ 可跳过排序,但 WHERE 条件(如status = 1)仍要全表过滤 - 有联合索引
(status, dept)→ 先用status = 1快速定位连续数据段,再在该段内按dept自然分组,一气呵成
联合索引怎么建才真正覆盖 GROUP BY 场景
关键不是“包含字段”,而是“顺序匹配访问路径”。索引列顺序必须服从查询中 WHERE 等值条件 → GROUP BY 字段 → (可选)ORDER BY 字段的逻辑链条。
- 查询是
SELECT dept, COUNT(*) FROM user WHERE status = 1 GROUP BY dept→ 建INDEX(status, dept),不是(dept, status) - 如果还带
ORDER BY dept DESC,且 MySQL 版本 ≥ 8.0,可用INDEX(status, dept DESC)避免filesort - 若
SELECT中还有MAX(created_at),而created_at不在索引里 → 回表开销大,考虑扩展为INDEX(status, dept, created_at)(覆盖索引) - 切忌把非等值条件(如
time > '2025-01-01')放在联合索引最左 → 它会截断索引,后面字段失效
哪些写法会让索引彻底失效
即使索引建对了,SQL 写法不对照样白搭。常见“自废武功”操作:
-
SELECT name, COUNT(*) FROM user GROUP BY dept→name既不在GROUP BY里,也没套聚合函数,MySQL 5.7+ 严格模式直接报错;宽松模式下强制走临时表 -
GROUP BY UPPER(dept)→ 函数包裹字段,索引无法匹配,除非建函数索引(MySQL 8.0.13+) -
WHERE dept LIKE '%tech'→ 左模糊,索引失效;改用前缀匹配dept LIKE 'tech%'才能用上 -
GROUP BY dept ORDER BY COUNT(*) DESC→COUNT(*)是计算值,不可能被索引覆盖,必然触发filesort,别硬优化
EXPLAIN 里怎么看 GROUP BY 是否走索引
盯死 type 和 Extra 两列:
-
type: index或range(不是ALL),且key显示用了哪个索引 → 成功走索引 -
Extra里没有Using temporary和Using filesort→ 分组和排序都由索引承担 - 如果
rows值远小于表总行数,说明 WHERE 条件已高效过滤 → 索引设计合理 - 注意
key_len:它告诉你实际用了索引的前几列,比如索引是(a,b,c),key_len = 4表示只用了a(假设a是 INT),b和c没参与,可能分组或排序仍会出问题
真正难的不是建索引,而是判断 WHERE 和 GROUP BY 的字段组合是否构成“可截断+可排序”的连续索引区间。很多慢查卡在“以为建了索引就万事大吉”,却忽略了等值条件的位置和字段顺序的刚性约束。


















