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,说明既做了排序又建了临时表,多见于分组与排序组合的写法,优先检查分组键与排序键能否共用一个索引。