首页/数据/数据库速查/排序与临时表:filesort 与 temporary 的优化
SQL 语法52 条

排序与临时表:filesort 与 temporary 的优化

ORDER BY / GROUP BY / DISTINCT 无索引支撑会走 filesort 或临时表;优化方向是让排序分组列与索引前缀对齐。

数据库速查数据更新于 2026-10-13

排序与临时表的代价

当 ORDER BY、GROUP BY 或 DISTINCT 缺少可用索引时,MySQL 只能把结果放入排序缓冲区做 filesort,或者建立临时表来完成分组与去重。行数越多代价越大,而且排序与临时表都可能落盘。优化方向是让排序或分组列与索引前缀对齐,从根本上减少需要处理的行数。

基本信息

适用MySQL 5.7 / 8.0
判断入口EXPLAIN 的 Extra 出现 Using filesort 或 Using temporary
相关参数sort_buffer_size、tmp_table_size、max_heap_table_size
方向索引对齐、缩减结果集、减少排序行数

优化示例

优化示例
-- 待优化:按 user_id 过滤后按时间倒序,缺少匹配索引
EXPLAIN SELECT id FROM orders WHERE user_id=42 ORDER BY created_at DESC LIMIT 10;
-- 建立与过滤、排序列一致的联合索引
ALTER TABLE orders ADD INDEX idx_user_created (user_id, created_at);
-- 复合条件也要求顺序与查询一致,范围条件后的列无法用于排序
ALTER TABLE orders ADD INDEX idx_user_status_created (user_id, status, created_at);
-- 分组场景:确认分组列是否有可用索引
EXPLAIN SELECT status, COUNT(*) FROM orders GROUP BY status;
-- 显式观察临时表与排序是否消除
EXPLAIN FORMAT=JSON SELECT id FROM orders WHERE user_id=42 ORDER BY created_at DESC LIMIT 10\G

信号与对策

信号成因对策
Using filesort排序列没有索引可用按过滤列加排序列建立联合索引
Using temporary分组或去重需要临时结构确认分组列有索引,或改用覆盖索引
排序行数很大过滤条件不够精确先缩小结果集再排序
临时表落盘结果超过内存阈值缩减结果集,而不是一味调大缓冲区
排序方向不一致复合索引方向与排序要求不符8.0 可用降序索引解决

典型使用场景

  • 列表分页接口响应变慢,检查排序是否走 filesort
  • 报表分组查询,确认分组列是否有索引支撑
  • 上线前 SQL 评审,把排序与分组列为重点检查项
  • 大偏移量分页优化,考虑改用游标式分页
  • 索引设计:把过滤列与排序列组合成联合索引
小结果集上的 filesort 未必比走索引慢:排序代价由行数、缓冲区与结果大小共同决定,先量化再优化。
盲目调大 sort_buffer_size 或 tmp_table_size 会推高内存压力,参数要按并发量与实例总内存预算设置。

易错点

  • 只加索引不看排序方向:复合索引方向与 ORDER BY 不一致时依然会 filesort
  • 认为有索引就一定不排序:范围条件之后的列无法用于排序,索引顺序要与查询匹配
  • 分页用大偏移量:LIMIT 大偏移仍需扫描前面所有行,考虑改用游标式分页
  • 一味调大内存参数:并发高时反而加剧内存压力,可能触发更严重的性能问题

数据来源与参考

  • MySQL 8.0 Reference Manual: ORDER BY Optimization

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌