GROUP BY 变慢主因是执行计划出现Using temporary或Using filesort;需用EXPLAIN查Extra列,确保索引顺序与GROUP BY严格一致、避免范围条件中断最左前缀、禁用SELECT *、调优tmp_table_size等参数。

GROUP BY 变慢,八成是因为执行计划里出现了 Using temporary 或 Using filesort——这说明数据库正在用磁盘临时表或外部排序,而不是靠索引直接分组。
怎么看执行计划里有没有临时表和文件排序
直接跑 EXPLAIN,重点盯 Extra 列:
- 出现
Using temporary:MySQL 必须建内存/磁盘临时表来存中间分组结果,尤其是 GROUP BY 字段没索引、或字段顺序与索引不匹配时 - 出现
Using filesort:即使有索引,但索引不能支撑分组所需的物理顺序(比如 GROUP BY a, b,却只建了 (b, a)),就会额外排序 -
key为空或显示NULL:压根没走索引,全表扫描起步,临时表和排序必然跟上
别光看 type 是 index 就放心——它只表示扫了索引,不代表能跳过排序或临时表。
为什么加了索引还是出 Using temporary
索引存在 ≠ 能用于 GROUP BY。常见硬伤:
- GROUP BY 字段顺序和索引列顺序不一致,例如 SQL 是
GROUP BY status, category,索引却是(category, status)→ 不匹配,无法利用左前缀 - SELECT 中用了聚合函数依赖的非分组字段,比如
SELECT status, SUM(amount),但索引只建了(status)→amount得回表查,触发临时表 - WHERE 条件含范围查询(如
created_at > '2024-01-01'),且放在索引中间位置,导致后续 GROUP BY 字段失效,例如索引(shop_id, created_at, user_id),created_at是范围条件 →user_id部分索引用不上
怎么让 Using filesort 消失
本质是让数据在磁盘/内存中天然有序,省去额外排序步骤:
- 确保 GROUP BY 字段完全命中索引最左前缀,且顺序严格一致;例如
GROUP BY a, b, c,索引必须是(a, b, c)或(a, b, c, d),不能是(a, c, b) - 避免在 GROUP BY 中用函数,像
GROUP BY DATE(created_at)→ 索引失效,改用范围 WHERE + 原字段分组,或建生成列+索引(MySQL 5.7) / 函数索引(8.0+) - 如果业务真不需要结果有序,显式加
ORDER BY NULL,可抑制优化器自动补排序逻辑 - 注意隐式类型转换:WHERE 中传字符串匹配 BIGINT 字段(如
user_id = '123'),索引失效,连带 GROUP BY 失效
临时表大小和内存限制也得管
就算索引对了,tmp_table_size 和 max_heap_table_size 设太小,MySQL 还是会把本该放内存的临时表刷到磁盘,IO 拉垮性能:
- 查当前设置:
SHOW VARIABLES LIKE 'tmp_table_size'; - 临时调大测试(仅会话级):
SET SESSION tmp_table_size = 268435456;(256MB) - 但治标不治本——真正该优先做的,是让查询根本不用临时表
覆盖索引没建对、字段顺序错一位、WHERE 里混了个范围条件……这些细节一错,Using temporary 和 Using filesort 就稳稳蹲在 Extra 里,等你一条条核对索引定义和 SQL 写法。










