mysql 5.7中group by不走索引排序主因是优化器放弃loose/tight index scan,而非索引缺失;关键取决于sql是否满足索引下推条件:group by字段须严格匹配索引最左前缀顺序,order by字段必须是group by列或确定性聚合(如max(created_at)),且禁用only_full_group_by后仍需语义合法。

MySQL 5.7 的 GROUP BY 不走索引排序,是因为执行计划没选对
不是索引不能用,而是优化器在特定条件下主动放弃 Loose Index Scan 或 Tight Index Scan,转而走全表扫描 + 临时表。这和你有没有建索引、索引是否覆盖无关,关键看 SQL 写法是否满足索引下推的前置条件。
ORDER BY 字段不在 GROUP BY 中时,索引排序必然失效
比如 SELECT dept_id, name FROM employees GROUP BY dept_id ORDER BY name,name 既没出现在 GROUP BY 列表里,也不是聚合结果(如 MAX(name)),MySQL 就无法保证每组有唯一可比的 name 值——此时连语义校验都过不去,根本不会进入索引排序决策环节,直接报 1055 错误。
- 错误本质是
ONLY_FULL_GROUP_BY拒绝非法引用,不是“排序被忽略” - 即使你强行关掉
ONLY_FULL_GROUP_BY,ORDER BY name仍可能返回非预期值(每组随机一条的name) - 真正能触发索引排序的
ORDER BY字段,必须是GROUP BY列本身,或确定性聚合表达式(如ORDER BY MAX(created_at))
子查询中 ORDER BY 被忽略,是因为 derived_merge 优化绕过了排序
SELECT * FROM (SELECT * FROM orders ORDER BY created_at DESC) t GROUP BY customer_id 这类写法,在 MySQL 5.7+ 中大概率不生效。优化器启用 derived_merge 后,会把子查询合并进外层,ORDER BY 直接丢弃——EXPLAIN 里看不到 Using filesort,也看不到 DERIVED 行。
- 加
LIMIT(如LIMIT 999999999)能禁用derived_merge,强制保留子查询排序逻辑 -
HAVING 1=1也能干扰优化器判断,但属于副作用技巧,不可靠 - 更稳妥的做法是换用窗口函数(MySQL 8.0+)或关联子查询:
WHERE id IN (SELECT MAX(id) FROM orders GROUP BY customer_id)
GROUP BY 字段顺序与索引字段顺序不一致,索引排序就废了
假设你建了联合索引 INDEX idx_group_time (dept_id, created_at),但写成 GROUP BY created_at, dept_id ORDER BY created_at DESC,哪怕字段完全一样,顺序错一位,MySQL 就无法利用该索引做 Loose Index Scan。
- 索引排序要求
GROUP BY列必须按索引定义顺序出现,且连续(不能跳过前导列) -
GROUP BY dept_id可用idx_group_time;GROUP BY dept_id, created_at也可用;但GROUP BY created_at就不行 - 如果真要按时间分组并排序,优先建
INDEX (created_at, dept_id),再写GROUP BY created_at
实际执行时,EXPLAIN 输出里是否带 Using temporary; Using filesort 是最直接的判断依据。别只看有没有索引,得看优化器到底选没选它。











