order by 默认升序,desc 必须显式书写;多列排序优先级由字段顺序决定,方向关键字仅作用于左侧字段;null 排序行为因数据库而异,需显式控制;表达式或函数排序易导致索引失效。

ORDER BY 默认是升序,但 DESC 必须显式写
很多人以为 ORDER BY salary DESC 和 ORDER BY salary DSC 差不多,结果报错——DSC 根本不是关键字,只有 DESC 才有效。升序可以省略 ASC,但降序漏写或拼错,查询就按默认升序跑,数据看起来“没排对”,其实是方向错了。
-
ASC可省略,但显式写出更利于团队协作和后期维护 - 数字、日期、字符串的升序逻辑一致:数值从小到大,日期从早到晚,字符串按当前排序规则(如 A→Z)
- 不同数据库对 NULL 的默认位置不一致:MySQL/PostgreSQL 升序时 NULL 在最后,Oracle/SQL Server 降序时 NULL 在最前——别依赖“看起来对”,要测试实际行为
多列排序的优先级由字段顺序决定,不是由 ASC/DESC 决定
写 ORDER BY department ASC, salary DESC,意思是“先严格按 department 升序分组,组内再按 salary 降序”。如果把字段顺序颠倒成 salary DESC, department ASC,结果就完全不一样:高薪者全排前面,不管部门,只在薪资相同时才看部门。
- 排序字段越靠左,优先级越高;方向关键字(
ASC/DESC)只作用于它左边紧邻的那个字段 - 混合方向很常见,比如
ORDER BY status ASC, updated_at DESC:先把待处理(status=0)的记录顶上来,再按更新时间倒序,确保最新待办优先 - 别用列位置编号(如
ORDER BY 2)——可读性差,SELECT 列顺序一调就崩,且多数规范禁用
按计算字段或隐藏字段排序完全合法,但要注意索引失效
你可以 ORDER BY price * quantity,也可以 ORDER BY email 却不在 SELECT 里选 email——SQL 允许这样。但代价是:这类表达式无法走索引,大数据量时可能触发全表排序,响应明显变慢。
- 函数包裹会直接让索引失效,比如
ORDER BY UPPER(name),即使name有索引也用不上 - 派生列排序建议提前物化:如果频繁按
LENGTH(name)排序,考虑加个计算列并建索引(MySQL 5.7+ 支持STORED列) - 用
COLLATE强制排序规则(如ORDER BY name COLLATE utf8mb4_0900_as_cs)能解决大小写敏感问题,但同样绕过索引,慎用
NULL 值排序行为因库而异,需要显式控制才可靠
写 ORDER BY created_at DESC,你希望 NULL 排最后?那在 PostgreSQL 里得补上 NULLS LAST;在 MySQL 里它本来就在最后,但换到 SQL Server 就可能跳最前。不声明,等于把行为交给数据库实现细节。
- 标准 SQL 支持
NULLS FIRST/NULLS LAST,但 MySQL 目前不支持(截至 8.4),只能靠COALESCE(created_at, '1970-01-01')这类兜底技巧 - 业务上常需把 NULL 当“最低优先级”处理,比如未填写评分的用户排末尾:
ORDER BY score DESC, id ASC不够,得配合COALESCE(score, -1) - GROUP BY 后的
ORDER BY COUNT(*) DESC也会受 NULL 影响——如果分组字段本身含 NULL,那一整组可能被忽略或错位
排序看着简单,真正卡住人的往往是 NULL 处理、索引是否命中、以及跨库迁移时排序规则(collation)的隐式差异。写完 ORDER BY,最好用 EXPLAIN 看一眼执行计划,确认没走 filesort。










