order by 默认是升序(asc),例如 order by created_at 实际等价于 order by created_at asc;需降序时必须显式写 desc,如 order by created_at desc。

ORDER BY 默认是升序还是降序?
MySQL 的 ORDER BY 默认按**升序(ASC)**排列,不是降序。很多人写完 ORDER BY created_at 就默认是“最新在前”,结果发现最早的数据排第一——这就是踩了默认 ASC 的坑。
实操建议:
- 只要需要“时间倒序”“金额从高到低”这类场景,必须显式写
DESC,比如ORDER BY created_at DESC -
ASC可省略,但DESC不能省;省略不等于不存在,只是语法允许你偷懒 - 多个字段混合排序时,每个字段的升降序要单独指定:
ORDER BY status ASC, updated_at DESC
NULL 值在 ORDER BY 中怎么排?
MySQL 把 NULL 当作“最小值”处理:在 ASC 时排最前,在 DESC 时排最后。这和 PostgreSQL、Oracle 不同(它们默认把 NULL 当最大值),容易在迁移或对比查询结果时出偏差。
常见错误现象:
- 用
ORDER BY score DESC查排行榜,结果NULL分数的用户总在底部,挤走了真实低分用户 - 前端分页时第一页突然冒出一堆空数据,就是
NULL被当最小值顶上来了
解决办法:
- 用
IS NULL显式控制位置,例如ORDER BY score IS NULL, score DESC让NULL排最后 - 或者提前用
COALESCE(score, -1)填充,默认值要确保不影响业务逻辑
ORDER BY 字段没索引会多慢?
如果 ORDER BY 的字段没索引,MySQL 很可能触发 Using filesort——不是真去磁盘排序,而是在内存或临时文件里做二次排序,性能断崖式下跌。
使用场景判断:
- 单表小数据量(
- 配合
LIMIT也不保险:即使只查 10 条,MySQL 仍需先把全表排完再截取 -
WHERE + ORDER BY共用复合索引才高效,比如WHERE status = 'active' ORDER BY created_at DESC,索引应建为(status, created_at)
检查方法:执行 EXPLAIN SELECT ... ORDER BY ...,看 Extra 列是否含 Using filesort。
中文字段排序为什么乱?
直接 ORDER BY name 对中文列排序,结果可能是“张三”在“阿猫”前面——因为默认按字符编码(如 utf8mb4_bin)逐字节比,不是按拼音或笔画。
原因和选择:
- utf8mb4_general_ci 已废弃,不推荐;utf8mb4_unicode_ci 按 Unicode 排序,对中文支持一般
- 真正靠谱的是 utf8mb4_pinyin_ci(需安装插件)或 MySQL 8.0+ 的
utf8mb4_0900_as_cs(区分大小写+按字母序),但都不原生支持拼音首字母 - 最稳的方案:加一个生成列存拼音首字母,比如
first_pinyin CHAR(1) STORED AS (LEFT(UPPER(pinyin(name)), 1)),再给它建索引
临时应急可用 ORDER BY CONVERT(name USING gbk),但 GBK 编码有兼容风险,别上生产。
排序逻辑一旦涉及语言习惯,就不再是纯 SQL 问题,得结合业务预期、字符集、索引和可维护性一起权衡。最容易被忽略的,其实是开发时用测试数据看不出问题,等上线百万级中文名一排序,全乱套。










