mysql 5.7 多字段混合排序必然触发 using filesort,因其索引仅支持物理升序存储,无法满足方向不一致的有序扫描;单字段可后向扫描,但多字段混合方向(如 uid desc, created_at asc)直接退化为全量 filesort,导致性能断崖下跌。

MySQL 5.7 多字段混合排序必然触发 Using filesort
只要 ORDER BY 中出现不同方向的字段(比如 uid DESC, created_at ASC),而索引又是按默认升序建的((uid, created_at)),5.7 就完全无法复用索引顺序。它不会做方向适配,也不会后向扫描多字段组合——单字段可以后向扫,多字段混合方向直接退化为全量排序。你看到 EXPLAIN 的 Extra 列里反复出现 Using filesort,说明每条查询都在内存或磁盘里重新排一遍结果集,报表类查询动辄几万行,性能断崖式下跌。
覆盖索引失效导致回表+排序双重开销
5.7 不支持降序索引,迫使你只能建 (a, b) 升序索引。但报表常要 SELECT a, b, c FROM t WHERE a > ? ORDER BY a DESC, b ASC —— 这时即使 a, b 能走索引,c 还得回表取;更糟的是,因为排序不匹配,MySQL 先取出所有满足 WHERE 的行(可能上万),再在 server 层对全部行做 filesort,c 字段越大(如 TEXT),sort_buffer_size 越容易溢出,直接落盘合并,Sort_merge_passes 持续上涨。
GROUP BY + ORDER BY 场景下执行计划彻底失控
复杂报表常带分组聚合和排序,例如:SELECT dept, COUNT(*), AVG(salary) FROM emp WHERE hire_date >= '2020-01-01' GROUP BY dept ORDER BY AVG(salary) DESC。5.7 对这种组合毫无优化能力:它无法把 GROUP BY dept 和 ORDER BY AVG(salary) DESC 同时下推到索引;即使你在 (dept, hire_date) 上建了索引,AVG(salary) 的计算和排序仍需临时表 + filesort。更麻烦的是,5.7 没有直方图统计信息,优化器对 hire_date 范围的选择偏差大,容易误选全表扫描而非索引。
升级 8.0 前硬扛的临时解法效果有限
- 建
(a DESC, b ASC)索引?5.7 会悄悄抹掉DESC,实际还是(a ASC, b ASC),没用 - 用
ORDER BY a * -1强转?函数导致索引失效,key列变NULL - 调大
sort_buffer_size?每个连接独占,100 并发就吃光 800MB,还可能卡在 ptmalloc 分配上 - 加
LIMIT触发堆排序?仅当N明确且较小时有效,报表导出通常要全量,LIMIT不适用
真正卡点不在内存或参数,而在 5.7 的 B+ 树叶子节点压根不存降序数据——这个物理限制,任何 SQL 改写或配置调整都绕不过去。











