ORDER BY 慢八成因触发 Using filesort;需索引覆盖排序字段且顺序、方向严格匹配B+树有序性,否则即使有索引也会失效——如复合索引(a,b,c)仅支持ORDER BY a、a,b或a,b,c同向排序,WHERE条件非最左前缀或含函数/表达式时同样无法利用索引排序。
ORDER BY 慢,八成是因为触发了;只要让索引覆盖排序字段且顺序匹配,InnoDB 的 B+ 树天然有序性就能直接返回结果,根本不用临时表或内存排序。
为什么加了索引还是出现
常见误区是“只要 ORDER BY 字段有单列索引就行”,其实 InnoDB 要求更严格:
复合索引必须满足最左前缀,且字段顺序、升降序(
/
)与
完全一致 —— 例如索引是
,那
可用;但
或
就不行
WHERE 条件里用了非最左字段(如索引
,但查询写
),该索引无法用于排序
中含函数或表达式(
、
)—— 索引值 ≠ 计算值,优化器直接放弃走索引排序
多表 JOIN 后对被驱动表字段排序(比如
),InnoDB 通常不复用被驱动表索引做排序
里怎么看是否真走了索引排序
关键盯紧
列,不是看有没有索引,而是看它是否“下推”到了存储层:
:排序已由索引完成,最快路径
空(无 Extra):也表示排序走索引,只是没用到覆盖索引的全部字段
:明确警告:MySQL 正在回表取数据后二次排序,性能瓶颈就在这儿
同时出现
:WHERE 走了索引,但排序没走,说明索引设计没兼顾排序需求
注意:
值如果接近全表行数,再配合
,基本等于全量数据在内存或磁盘上重排。
哪些
场景注定绕不开
这些写法 MySQL 根本没法利用索引有序性,优化器会直接跳过索引排序逻辑:
MySQL(Linux)
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
下载
:每次都要随机打乱,无序可言
、
:函数破坏索引有序性
(而索引是
全 ASC):MySQL 5.7 不支持混合方向,8.0+ 才能建
匹配
:非驱动表字段排序,优化器通常拒绝用其索引做排序
这类场景要么重构查询逻辑(比如预计算并存字段),要么接受
并调优
和
。
用覆盖索引减少回表,顺便加速
即使排序本身走了索引,如果
字段不在索引里,InnoDB 还得根据主键回表捞数据 —— 这个过程在大偏移分页时尤其伤:
建联合索引时把常用查询字段一起带上,例如常查
,那就建
这样
的
会显示
,全程只走索引 B+ 树,不碰聚簇索引页
但注意:索引越宽,写入开销越大,且可能挤占 Buffer Pool;别把大字段(如
)塞进索引
真正难处理的是高偏移分页(
):即使走了索引,也要跳过前 10 万行主键,I/O 成本仍高。这时候光靠索引不够,得结合游标分页或延迟关联。
Using filesortUsing filesortASCDESCORDER BYINDEX(user_id ASC, created_at DESC)ORDER BY user_id, created_at DESCORDER BY created_at, user_idORDER BY user_id ASC, created_at ASC(a,b,c)WHERE b = 1ORDER BYORDER BY UPPER(name)ORDER BY a + 1JOIN orders ON users.id = orders.user_id ORDER BY orders.created_atEXPLAINExtraUsing indexUsing filesortUsing where; Using filesortrowsUsing filesortORDER BYfilesortORDER BY RAND()ORDER BY ABS(score)ORDER BY JSON_EXTRACT(data, '$.name')ORDER BY a, b DESC, c ASC(a,b,c)INDEX(a ASC, b DESC, c ASC)SELECT * FROM t1 JOIN t2 ON ... ORDER BY t2.xfilesortsort_buffer_sizemax_length_for_sort_dataORDER BYSELECTSELECT id, title, status FROM posts WHERE category = ? ORDER BY created_at DESCINDEX(category, created_at DESC, id, title, status)EXPLAINExtraUsing indexTEXTLIMIT 100000, 20