ORDER BY 是唯一可靠的结果集排序方式
MySQL 不保证查询结果的默认顺序——哪怕你刚插入完数据、没删没改,下次
SELECT *也可能顺序不同。这不是 bug,是存储引擎(如 InnoDB)按聚簇索引物理存放、B+ 树分裂/合并导致的自然现象。想让结果稳定有序,必须显式写
ORDER BY,别依赖“看起来排好了”。
多字段排序:优先级从左到右,相同才往下走
当用多个字段排序时,MySQL 严格按逗号分隔的顺序逐级生效,不是“一起算权重”。比如:
SELECT * FROM orders ORDER BY status DESC, created_at ASC;
它的意思是:
先按status降序排(比如 'shipped' > 'pending' > 'cancelled') 只有
status完全相同时,才启用
created_at升序(比如同为 'pending' 的订单,早创建的在前) 如果所有
status值都唯一,
created_at根本不会参与实际排序
常见错误是以为加了两个字段就“自动智能排序”,结果发现第二字段毫无影响——先检查第一字段是否真有重复值。
NULL 值默认排最前(升序)或最后(降序),但可被覆盖
在 MySQL 中,
NULL被视为“比所有非空值都小”,所以:
ORDER BY col ASC→
NULL排最前面
ORDER BY col DESC→
NULL排最后面
但业务中常需统一处理,比如把
NULL当作“未知”排末尾(无论升序降序)。可用
IS NULL配合布尔表达式“拉高优先级”:
SELECT * FROM users ORDER BY (age IS NULL) ASC, age ASC;
这行代码强制把非 NULL 的
age全部排在前面,再按数值升序;
NULL统一落在最后。
排序性能:没索引的 ORDER BY 很可能拖垮查询
如果
ORDER BY的字段没索引,MySQL 必须在内存或磁盘做 filesort —— 数据量稍大(比如 >10 万行)就会明显变慢,甚至触发
Using temporary; Using filesort的告警。 单字段排序:给该字段建普通索引即可,如
ALTER TABLE t_message ADD INDEX idx_created_at(created_at);多字段排序:索引必须**左前缀匹配**排序顺序,例如
ORDER BY a ASC, b DESC,对应索引应为
INDEX idx_a_b (a, b);注意:MySQL 8.0+ 支持混合方向索引(
(a ASC, b DESC)),但 5.7 及更早版本只认全部 ASC 或全部 DESC 避免在函数或表达式上排序,如
ORDER BY UPPER(name),无法走索引
真正容易被忽略的是:即使加了索引,若
WHERE条件用了范围查询(如
WHERE time > '2025-01-01'),后续的
ORDER BY字段大概率也用不上索引——这是 B+ 树索引的天然限制,得靠覆盖索引或重写查询逻辑来绕过。
