GROUP BY 是否走索引取决于是否满足“最左前缀+有序性”:字段须为索引最左连续前缀且未被函数、类型转换等破坏顺序;EXPLAIN中key有值但Extra含Using temporary或filesort,说明索引未有效支撑分组。

加索引不是万能的,但没索引的 GROUP BY 几乎必慢——只要 EXPLAIN 里出现 Using temporary,说明 MySQL 正在硬扛全表扫描 + 内存/磁盘临时表,数据量一过百万,响应直接掉到秒级。
怎么确认是 GROUP BY 没走索引?
看 EXPLAIN FORMAT=TREE(MySQL 8.0+)或传统 EXPLAIN 的两处关键输出:
-
type是ALL或index(非ref/range),说明没用上有效索引 -
Extra列含Using temporary,就是分组被迫建临时表的铁证 -
rows显示扫描行数远大于实际分组数(比如扫 300 万行只出 12 个分组),说明 WHERE 过滤没生效或索引没覆盖条件
建什么索引才真正起作用?
单列索引基本无效;必须用复合索引,且顺序不能错:
- 最左是
WHERE等值条件字段(如status = 'paid') - 紧接是
GROUP BY字段(如user_id),顺序必须和GROUP BY子句完全一致 - 末尾补上聚合需要的列(覆盖索引):对
COUNT(*)只需分组字段本身;对SUM(amount)必须把amount加进索引
错误示例:INDEX idx_user_status (user_id, status) 对 WHERE status = ? GROUP BY user_id 几乎无用——MySQL 无法跳过 user_id 去按 status 过滤。
正确写法:CREATE INDEX idx_status_user_amount ON orders (status, user_id, amount);
ORDER BY 和 GROUP BY 混用时为什么还慢?
哪怕索引建得再准,ORDER BY COUNT(*) DESC 这类写法也必然触发 Using filesort:
-
COUNT(*)是聚合结果,不在原始索引中,MySQL 无法靠索引顺序直接排序 -
ORDER BY NULL只能禁用结果集排序,不解决临时表和回表问题 - 如果业务真要 Top N 分组结果,别硬扛实时查:用定时任务把
GROUP BY结果写入汇总表,再对汇总表加索引
哪些写法会让索引彻底失效?
这些看似无害的操作,会直接让已有索引作废:
-
GROUP BY DATE(create_time)→ 改用生成列:ALTER TABLE logs ADD COLUMN create_date DATE AS (DATE(create_time)) STORED,再对create_date建索引 -
WHERE id = '123'(id是INT)→ 改成WHERE id = CAST('123' AS UNSIGNED),避免隐式类型转换 -
GROUP BY UPPER(name)→ 不要函数包装,改在写入时标准化存储 - 把
TEXT或长VARCHAR字段塞进索引 → 写入开销陡增,缓存效率暴跌
真正卡住性能的,往往不是语法本身,而是索引是否“覆盖”了整个执行路径——从过滤、分组到聚合,缺一不可。一旦数据量上亿,光靠索引只能延缓恶化,预聚合才是硬解。


















