首页/数据/数据库速查/ORDER BY 排序与多列排序
SQL 语法52 条

ORDER BY 排序与多列排序

按一列或多列排序,支持 ASC/DESC 与表达式;排序列有合适索引时可用索引顺序避免 filesort。

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

ORDER BY 是什么

ORDER BY 决定结果集的排列顺序,可以按一列或多列排序,每列单独指定升序或降序,执行位置在 SELECT 计算与 HAVING 之后、LIMIT 之前。它的性能关键只有一句话:能否顺着索引读。排序键与索引顺序和方向一致时,MySQL 直接按索引顺序返回,执行计划里看不到额外排序;不一致就只能把结果取出来重排,也就是 Using filesort,这时结果集越大代价越高。

基本信息

用途结果排序,保证分页与导出的稳定顺序
语法ORDER BY 列1 [ASC|DESC], 列2 [ASC|DESC]
默认方向ASC,不写即升序
可排序对象列名、列别名、表达式、FIELD() 自定义顺序
索引配合排序方向与索引定义一致才能免排序
执行位置SELECT 之后、LIMIT 之前,因此可以引用列别名

典型使用场景

  • 列表页按时间倒序展示最新数据,排序字段通常需要索引支撑
  • 导出报表时固定顺序,便于人工核对与下游比对
  • 按业务优先级排序,例如用 FIELD() 指定状态先后的自定义顺序
  • 分页查询必须带排序,否则翻页结果无序、可能出现重复
  • 排查同一条数据时而排前时而排后:多数是排序键不唯一导致的并列
  • 排序叠加 LIMIT 取 TopN(金额、耗时、数量),依赖索引避免全量排序

常用示例

常用示例
SELECT id, qty FROM orders ORDER BY qty DESC;   # 单列降序
SELECT id FROM orders ORDER BY status, created_at DESC LIMIT 50;   # 多列混合方向
SELECT id FROM orders ORDER BY FIELD(status,'pending','paid','shipped');   # 按业务优先级排序
SELECT id, amount FROM orders WHERE user_id = 1001 ORDER BY created_at DESC LIMIT 20;   # 等值过滤加排序
SELECT id FROM orders ORDER BY created_at DESC, id DESC LIMIT 20;   # 补唯一列,分页才稳定

配合索引

配合索引
ALTER TABLE orders ADD INDEX idx_status_created (status, created_at DESC);   # 8.0 降序索引,方向与查询一致
EXPLAIN SELECT id FROM orders WHERE status='paid' ORDER BY created_at DESC LIMIT 20;   # 看 Extra 是否还有 Using filesort

执行计划现象读法

现象含义处理
Extra 显示 Using filesort无法借助索引顺序,需额外排序核对排序键与索引的顺序、方向是否一致
Extra 显示 Using index覆盖索引直接返回,未回表理想状态,查询列都在索引上
Using temporary分组或去重引入临时表常与 GROUP BY、DISTINCT 一同出现
排序前结果集很大先排序再截断的成本高先用过滤条件收窄,再排序取前 N
并列值顺序随机排序键不唯一追加唯一列作为最后一个排序键
ORDER BY 表达式表达式无法借用索引顺序确有必要时用冗余列存计算结果
排序方向必须与索引匹配:复合索引 (status, created_at DESC) 能支撑 WHERE status=? ORDER BY created_at DESC 免排序;若查询要求 created_at 升序而索引是降序,仍然会走额外排序。
只写 ORDER BY 不带 LIMIT 时,服务端要完成全量排序再返回;大结果集导出容易把临时空间撑大,导出场景建议按主键范围分批拉取。
分页依赖排序的稳定性:排序键不唯一时,并列行的返回顺序不保证一致,用户翻页会看到重复或漏掉的记录,必须在末尾追加唯一列。

排序写法检查清单

  • 排序字段尽量落在同一张表上,跨表排序必然引入临时表
  • 复合索引上的排序键要连续出现,中间跳过的列会让索引顺序用不上
  • 排序后只取固定条数时把 LIMIT 写上,配合索引可以提前停止扫描
  • 需要多个方向混排时,8.0 可用降序索引匹配,5.7 只能接受额外排序
  • 导出与对账固定排序键并补唯一列,避免两次导出顺序不一致
  • 排序键出现在函数或表达式里时,考虑用冗余列存计算结果
执行计划里同时出现 Using filesort 与 Using temporary,说明既做了排序又建了临时表,多见于分组与排序组合的写法,优先检查分组键与排序键能否共用一个索引。

易错点

  • 以为加了 LIMIT 就一定少排序:排序在截断之前执行,没有索引可借时依然要处理整个结果集
  • 排序键与索引方向不一致:查询写升序、索引建降序,照样出现额外排序,索引白建
  • 只按非唯一列排序就分页:并列行的顺序不确定,翻页出现重复或漏行,需补唯一列收尾
  • 大结果集排序导出且不分批:临时表与磁盘空间被占满,可能直接触发实例磁盘告警
  • 用列序号或表达式排序却指望走索引:优化器无法借助索引顺序,需要通过冗余列或改写查询解决

数据来源与参考

  • MySQL 8.0 Reference Manual: ORDER BY Optimization

相关工具

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