多字段排序优先级从左到右依次生效,先按首字段排序,值相同时再按次字段排序;各字段升降序需显式指定,默认ASC。

多字段排序不是“多个字段一起排”,而是按从左到右的顺序逐级生效——左边字段决定大分组,右边字段只在左边值相同时才起作用。
ORDER BY 字段顺序直接决定业务逻辑是否正确
比如想查“每个状态里最新的一条记录”,排序必须写成 ORDER BY status, created_at DESC;如果写反了 ORDER BY created_at DESC, status,结果就是“所有记录按时间倒序,状态只是时间相同时的补充”,完全偏离本意。
- 字段位置 = 优先级:第一个字段排完,只对相同值的行再用第二个字段排
- 常见翻车点:把时间字段放前面,但业务实际要的是“按类型分组后看各自最新”
- 验证方法:手动挑几行
status相同的数据,看它们内部是否真按created_at DESC排
ASC/DESC 必须为每个字段单独声明,不能省略也不能挪位
ORDER BY name, age DESC 中,name 是默认 ASC,age 是显式 DESC;但如果你本意是两个都降序,漏写 name DESC,结果就全乱了。
- 不写方向 =
ASC,不是“忽略”,也不是“继承前一个” - 错误示范:
ORDER BY name DESC, age→name降序、age升序(很多人以为逗号后统一生效) - 安全写法:所有字段都显式写方向,如
ORDER BY name DESC, age DESC
含 NULL 值的字段排序行为因数据库而异,必须显式控制
MySQL 把 NULL 当最小值,ASC 时排最前;PostgreSQL 默认当最大值,ASC 时排最后。跨库迁移或联合查询时,结果可能突变。
- MySQL 5.7+ 兼容写法:
ORDER BY (deadline IS NULL), deadline ASC(FALSE=0在前,TRUE=1在后) - PostgreSQL 推荐写法:
ORDER BY deadline ASC NULLS LAST - 通用兜底方案:
ORDER BY CASE WHEN deadline IS NULL THEN 1 ELSE 0 END, deadline ASC
复合索引是否生效,取决于 ORDER BY 字段顺序和方向是否严格匹配
即使你写了 ORDER BY a ASC, b DESC,但索引是 (a ASC, b ASC),MySQL 就无法用索引完成排序,会触发 filesort。
- 索引字段顺序必须和
ORDER BY一致,不能跳过前导列(比如索引是(a,b),但ORDER BY b就用不上) - 方向也要一致:索引
(a ASC, b DESC)才能支持ORDER BY a ASC, b DESC - 用
EXPLAIN看Extra列是否有Using filesort,有就是没走索引排序
最容易被忽略的是:ORDER BY 中字段的语义优先级和物理顺序必须对齐,而不是看着“都写了”就放心——少一个 DESC、错一位顺序、漏处理 NULL,都可能让分页错位、TOP-N 拿错数据、报表排序颠倒。










