GROUP BY 能用上索引需满足:所有分组列必须为同一索引的最左连续前缀,且索引类型支持有序访问(如BTREE);WHERE中若含范围条件,其后分组列通常失效;避免前缀索引和中间列跳过。

GROUP BY 能用上索引的几个硬条件
GROUP BY 不是“有索引就能加速”,它对索引结构非常挑剔。最常见失效场景是:明明建了索引,EXPLAIN 里还是出现 Using temporary。
- 必须满足最左前缀匹配:比如索引是
(dept, role, salary),那GROUP BY dept可以用,GROUP BY role就完全失效 - 不能跳过中间列:
GROUP BY dept, salary在上述索引上会失效,因为role被跳过了 - WHERE 条件中非等值过滤(如
>、BETWEEN、IN)后,后续 GROUP BY 列大概率无法利用索引顺序 —— MySQL 5.7 中尤其明显,8.0+ 有松散索引扫描优化,但仅限MIN/MAX且无其他聚合函数 - 避免前缀索引:对
VARCHAR(255)字段只建INDEX(name(10)),GROUP BY name 时无法保证分组一致性,索引会被忽略
ORDER BY 索引生效的关键顺序
ORDER BY 要走索引,本质是让 MySQL 按索引物理顺序直接读取,省掉 Using filesort。但它不认“逻辑顺序”,只认“B+树存储顺序”。
- 联合索引
(a, b, c)只能支持这些排序:ORDER BY a、ORDER BY a,b、ORDER BY a,b,c;ORDER BY b,c或ORDER BY c全部失效 - 混合方向要严格一致:MySQL 8.0+ 支持
CREATE INDEX idx ON t (a ASC, b DESC),但查询必须写成ORDER BY a ASC, b DESC;写成ORDER BY a DESC, b ASC仍触发Using filesort - WHERE + ORDER BY 组合时,等值条件列必须连续前置:比如
WHERE a = ? AND b > ? ORDER BY c,索引(a,b,c)可用;但WHERE a = ? AND c = ? ORDER BY b就不行 —— 因为c在索引中位于b之后,破坏了b的有序性
GROUP BY 和 ORDER BY 共用一个索引的陷阱
很多人试图用单个联合索引同时覆盖二者,结果发现执行计划里依然出现 Using temporary; Using filesort。问题往往出在字段顺序和用途冲突上。
- 索引列顺序必须同时满足 GROUP BY 和 ORDER BY 的语法顺序,且不能有“断层”。例如查询
SELECT dept, AVG(salary) FROM emp GROUP BY dept ORDER BY hire_date DESC,索引(dept, hire_date)是错的 —— GROUP BY 只用到dept,但 ORDER BY 要的是hire_date,而它不在 GROUP BY 后紧邻位置,MySQL 无法保证分组内hire_date有序 - 更稳妥的做法是:GROUP BY 字段放最前,ORDER BY 字段紧随其后,且所有 SELECT 字段最好都包含进去(覆盖索引)。比如
SELECT dept, MAX(hire_date) FROM emp GROUP BY dept ORDER BY MAX(hire_date) DESC,对应索引应为(dept, hire_date) - 如果 GROUP BY 和 ORDER BY 字段完全不同(如
GROUP BY dept但ORDER BY created_at),基本无法用单索引兼顾,要么接受Using filesort,要么加物化视图或冗余字段预计算
别忽略 sort_buffer_size 和回表成本的影响
即使索引结构完全正确,MySQL 优化器也可能主动放弃使用它 —— 尤其当它预估回表代价太高时。
- 比如
SELECT * FROM emp ORDER BY name,哪怕name有索引,优化器发现要回表取全部字段太贵,可能宁愿全表扫描 +Using filesort - 加上
LIMIT 10后,优化器常会改选索引,因为只需回表 10 行;但去掉LIMIT,就很可能退回到全表扫描 -
sort_buffer_size设置过小会导致磁盘临时文件,此时即便走了索引,整体性能也卡在 I/O 上;可临时调大验证,但注意这是 per-connection 参数,高并发下易内存溢出
索引不是开关,是契约:你按什么顺序建,MySQL 就按什么顺序用。任何一处列顺序、等值/范围条件、升降序混搭的偏差,都会让这个契约失效。实际调优时,永远以 EXPLAIN 的 key 和 Extra 字段为准,而不是“我以为它该走索引”。

















