using filesort 表示 mysql 无法用索引直接排序,需额外排序操作;常见原因包括 order by 字段无索引、索引不匹配、select * 导致覆盖索引失效、范围查询中断索引、类型不一致等。

ORDER BY 没走索引?先看执行计划里的 Using filesort
只要 EXPLAIN 结果中出现 Using filesort,就说明 MySQL 没法用索引直接完成排序,得把数据捞出来再内存或磁盘排序——这是性能瓶颈的明确信号。
常见诱因包括:
-
ORDER BY字段没建索引,或索引不匹配(比如复合索引(a, b),却只按b排序) - 查询里混用了
SELECT *和ORDER BY,导致覆盖索引失效 -
WHERE条件用了范围查询(如a > 100),之后的索引字段无法用于排序 - 排序字段类型与索引字段类型不一致(比如索引是
VARCHAR(50),ORDER BY却隐式转成VARCHAR(10))
复合索引怎么建才让 ORDER BY 走索引?
核心原则:索引顺序 = WHERE 等值条件字段 + ORDER BY 字段(且不能有范围条件隔开)。
例如查询:SELECT id, name FROM users WHERE status = 1 ORDER BY created_at DESC
应建索引:INDEX (status, created_at) —— 这样能同时满足过滤和排序。
注意这些细节:
- 如果
ORDER BY是created_at ASC, id DESC,索引也得严格对应方向(MySQL 8.0+ 支持混合方向,但 5.7 只支持全 ASC 或全 DESC) -
WHERE中有多个等值条件(status = 1 AND type = 'vip'),索引字段顺序不影响过滤效率,但建议把高频过滤字段放前 - 避免在索引里包含太多字段,尤其是大字段(如
TEXT),会拖慢写入和索引体积
分页深翻(OFFSET 大)为什么慢?用游标替代
LIMIT 10000, 20 慢,不是因为取 20 行,而是 MySQL 必须先扫描前 10000 行并丢弃——即使有索引,也是“跳着扫”。
更优解是游标分页(cursor-based pagination):
- 首次查:
SELECT id, name, created_at FROM posts ORDER BY created_at DESC LIMIT 20 - 下一页传上一页最后一条的
created_at和id:SELECT id, name, created_at FROM posts WHERE created_at - 关键点:WHERE 条件必须能利用索引,ORDER BY 字段必须是索引前缀
临时表排序撑爆内存?调小 sort_buffer_size 反而更快
很多人以为把 sort_buffer_size 调大就能加速排序,实际容易适得其反:单个连接独占该内存,设太大反而导致并发时内存争抢、触发 swap。
合理做法:
- 线上环境一般设为
2M~4M(默认通常是 256K,太小会导致频繁磁盘排序) - 确认是否真需要全局调大:先用
SHOW PROFILE FOR QUERY N看Sorting result阶段耗时占比 - 更治本的是减少参与排序的数据量——加更精准的
WHERE条件,或改用覆盖索引避免回表
真正卡住的往往不是排序本身,而是排序前没过滤干净的数据流。索引设计和查询写法,比调参重要得多。










