group by 能走索引是因为利用b+树索引的有序性直接遍历分组,避免临时表和文件排序;前提是group by字段必须严格匹配索引最左前缀且顺序一致,同时where条件字段需前置,避免函数、表达式或隐式转换破坏索引连续性。

GROUP BY 为什么能走索引?
MySQL 的 GROUP BY 不是“自动走索引”,而是依赖索引的物理顺序来避免排序和临时表。当索引列顺序与 GROUP BY 字段完全一致时,引擎可直接按索引遍历完成分组——本质是利用了 B+ 树的有序性,跳过 Using temporary 和 Using filesort。
关键点:索引必须满足最左前缀法则,且字段顺序要严格匹配 GROUP BY a, b → 索引必须是 (a, b),(a, b, c) 也可,但 (b, a) 或 (a) 单独对 GROUP BY a, b 无效。
WHERE + GROUP BY 联合索引怎么建?
90% 的慢查询问题出在没把 WHERE 条件字段“前置”进索引。因为 WHERE 过滤发生在 GROUP BY 之前,索引需先定位符合条件的行,再按分组字段顺序组织。
- 写法:
SELECT city, COUNT(*) FROM user WHERE status = 'active' GROUP BY city; - 正确索引:
(status, city)——status在前,city在后 - 错误索引:
(city, status)或单独(city):无法加速WHERE过滤,仍会全表扫描或回表 - 若还查
AVG(age),建议扩展为(status, city, age)形成覆盖索引,避免回主表读取
哪些写法会让索引彻底失效?
函数、表达式、类型隐式转换都会打断索引的连续访问路径,强制退化为全表扫描+内存/磁盘排序。
-
GROUP BY YEAR(create_time)→ 索引失效;改用WHERE create_time >= '2024-01-01' AND create_time (配合生成列或分区) -
GROUP BY CONCAT(first_name, last_name)→ 无法索引;应提前计算并存入冗余字段full_name,再建索引 -
GROUP BY CAST(user_id AS CHAR)→ 类型转换导致索引失效;保持原始类型分组 -
GROUP BY BINARY name或大小写敏感操作,可能绕过普通索引;确认 collation 是否匹配
如何验证索引是否真起作用?
别只看“有没有索引”,要看执行计划里有没有 Using temporary 和 Using filesort —— 这俩出现一个,基本就宣告优化失败。
运行 EXPLAIN SELECT ... GROUP BY ...,重点观察:
-
type字段最好是ref或range,不是ALL -
key显示实际使用的索引名 -
Extra中不能含Using temporary(表示用了临时表)、Using filesort(表示额外排序) - 如果
rows显示扫描行数接近总行数,说明索引没生效或选择性差
真正容易被忽略的是:即使 GROUP BY 字段有索引,只要前面 WHERE 条件没覆盖,或者顺序错位,索引就形同虚设。优化不是加个索引就完事,得卡准执行路径的每一步。











