MySQL 中 ORDER BY 的用法详解
ORDER BY 是 MySQL 中用于对查询结果进行排序的关键字,支持单列、多列、表达式排序,并能结合索引优化性能。以下从基础语法到高级用法全面解析。
一、基础语法
SELECT column1, column2, ...
FROM table_name
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;
-
ASC:升序(默认,可省略)。
-
DESC:降序。
-
支持按多列排序,优先级从左到右。
二、单列排序
按单个字段排序:
-- 按年龄升序(默认)
SELECT name, age FROM users ORDER BY age;
-- 按注册时间降序
SELECT name, signup_date FROM users ORDER BY signup_date DESC;
三、多列排序
按多字段排序,先按第一个字段排序,相同值再按第二个字段排序:
-- 先按部门升序,同部门按工资降序
SELECT name, department, salary
FROM employees
ORDER BY department ASC, salary DESC;
四、按表达式或函数排序
排序依据可以是表达式或函数计算结果:
-- 按名字长度排序
SELECT name FROM users ORDER BY LENGTH(name) DESC;
-- 按日期部分排序(仅年份)
SELECT event_name, event_date
FROM events
ORDER BY YEAR(event_date) DESC;
-- 条件排序(CASE语句)
SELECT product, stock
FROM products
ORDER BY
CASE
WHEN stock = 0 THEN 1
ELSE 0
END,
product_name;
五、处理 NULL 值
MySQL 默认将 NULL 视为最小值:
-
升序:NULL 出现在结果开头。
-
降序:NULL 出现在结果末尾。
自定义 NULL 位置(需通过表达式):
-- 将 NULL 的 age 放在最后(升序)
SELECT name, age
FROM users
ORDER BY
CASE WHEN age IS NULL THEN 1 ELSE 0 END,
age ASC;
六、结合 LIMIT 分页
获取排序后的前 N 条记录或分页:
-- 获取工资最高的前5名员工
SELECT name, salary
FROM employees
ORDER BY salary DESC
LIMIT 5;
-- 分页(第2页,每页10条)
SELECT name
FROM users
ORDER BY id
LIMIT 10 OFFSET 10; -- 跳过前10条,取接下来10条
七、性能优化与索引
1. 索引对排序的影响
-
若
ORDER BY
字段有索引,且顺序与索引一致,可避免文件排序(Using filesort)。 -
复合索引顺序需匹配:索引
(a, b)
对ORDER BY a, b
有效,但对ORDER BY b, a
无效。
示例:
-- 创建复合索引
CREATE INDEX idx_dept_salary ON employees (department, salary);
-- 使用索引优化排序
SELECT * FROM employees
ORDER BY department, salary; -- 命中索引,无需额外排序
2. 避免文件排序
当无法使用索引时,MySQL 会使用临时表排序(Using filesort
),可通过以下方式优化:
-
增大
sort_buffer_size
参数。 -
减少查询字段数量(避免
SELECT *
)。
八、子查询中的 ORDER BY
子查询内的 ORDER BY
通常需结合 LIMIT
才生效:
-- 无效(外部查询会打乱顺序)
SELECT * FROM (
SELECT * FROM users ORDER BY id DESC
) AS sub;
-- 有效(使用LIMIT保留顺序)
SELECT * FROM (
SELECT * FROM users ORDER BY id DESC LIMIT 100
) AS sub;
九、高级用法
1. 按字段的特定值排序
-- 按特定状态顺序排序(例如:'active' > 'pending' > 'expired')
SELECT status, task
FROM tasks
ORDER BY
FIELD(status, 'active', 'pending', 'expired');
2. 随机排序
-- 随机获取10条记录
SELECT name
FROM products
ORDER BY RAND()
LIMIT 10;
十、常见问题与解决方案
-
排序结果不稳定
-
现象:相同排序列值的记录顺序不一致。
-
解决:添加唯一列(如主键)作为次要排序条件。
-
-
分页重复数据
-
现象:翻页时出现重复记录。
-
解决:确保排序条件唯一(例如
ORDER BY id, create_time
)。
-
-
性能瓶颈
-
现象:大表排序慢。
-
解决:
-
创建合适索引。
-
使用覆盖索引(仅查询索引字段)。
-
分阶段排序(先过滤再排序)。
-
-
十一、示例汇总
-- 多列排序 + 表达式
SELECT name, price, stock
FROM products
ORDER BY
CASE WHEN stock > 0 THEN 0 ELSE 1 END,
price DESC;
-- 结合聚合函数排序
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
ORDER BY avg_salary DESC;
-- 处理 NULL 并分页
SELECT product, rating
FROM reviews
ORDER BY
CASE WHEN rating IS NULL THEN 1 ELSE 0 END,
rating DESC
LIMIT 10 OFFSET 20;
十二、总结
-
核心功能:ORDER BY 提供灵活的结果排序,支持单列、多列、表达式和函数。
-
性能关键:合理利用索引避免文件排序,大表查询优先优化索引和过滤条件。
-
高级技巧:通过 CASE、FIELD 或子查询实现复杂排序逻辑。
-
注意事项:处理 NULL 值、分页稳定性及子查询中的排序限制。