Using temporary和Using filesort主因是GROUP BY字段顺序与索引最左前缀不匹配;必须严格按WHERE等值条件、GROUP BY字段、ORDER BY字段顺序创建联合索引,且禁用函数分组。

GROUP BY列顺序不匹配索引最左前缀,MySQL直接弃用索引
执行计划里出现 Using temporary 或 Using filesort,八成是因为 GROUP BY 字段顺序和索引定义顺序对不上。MySQL 不会“重排”索引字段来适配你的分组顺序——它只认严格一致的最左连续前缀。
-
GROUP BY user_id, status只能用索引(user_id, status)或(user_id, status, created_at),而(status, user_id)完全无效 - 哪怕你只写
GROUP BY user_id,也必须是索引的最左列;如果索引是(status, user_id),那这个单列分组也走不了索引 - 索引
(a, b, c)支持GROUP BY a、GROUP BY a, b、GROUP BY a, b, c,但不支持GROUP BY a, c(跳过b就断链)
WHERE + GROUP BY 组合决定索引字段排列逻辑
执行计划不是只看 GROUP BY,而是通盘考虑访问路径:先过滤,再分组,最后可能排序。索引字段顺序必须按这个链条排布,否则后半段就失效。
- 查询
SELECT user_id, COUNT(*) FROM orders WHERE shop_id = 123 GROUP BY user_id,理想索引是(shop_id, user_id),不是(user_id, shop_id) - 如果加了范围条件,比如
WHERE created_at >= '2024-06-01',它必须放在索引末尾,否则后面的GROUP BY字段无法利用索引顺序 - 错误索引
(created_at, shop_id, user_id):因为created_at是范围查询,shop_id和user_id实际上都用不上
函数或表达式会让GROUP BY彻底失去索引能力
只要 GROUP BY 里出现函数调用,MySQL 就无法复用原字段索引,执行计划必然退化为临时表 + 全量扫描。
-
GROUP BY DATE(created_at)再常见不过,但它让created_at索引完全失效 - MySQL 5.7 必须靠生成列 + 索引绕过,例如新增
created_date DATE AS (DATE(created_at)),再建索引(created_date) - MySQL 8.0+ 支持函数索引:
CREATE INDEX idx_created_date ON orders ((DATE(created_at))),但注意括号写法不能漏
ORDER BY 和 GROUP BY 共用索引时,顺序错一位就触发二次排序
如果同时有 GROUP BY a, b 和 ORDER BY a, b,MySQL 才可能复用同一索引完成分组和排序;顺序稍有偏差,就会在 Extra 里看到 Using filesort。
-
GROUP BY a, b ORDER BY b, a→ 必然Using filesort,因为索引物理顺序不匹配输出要求 -
GROUP BY a, b ORDER BY a, b, c:只有索引是(a, b, c)才能避免排序;若索引是(a, b),c无索引支撑,仍要排序 - 别依赖 MySQL 8.0 默认按分组键排序的行为——显式写
ORDER BY NULL虽能去掉Using filesort,但解决不了Using temporary的根本问题

















