mysql执行SQL时排序发生在哪一步_order by流程解析

来源:这里教程网 时间:2026-02-28 20:40:44 作者:

ORDER BY 是在 WHERE 和 GROUP BY 之后执行的

MySQL 执行 SQL 时,

ORDER BY
发生在逻辑处理流程的靠后阶段:它**不会影响 WHERE 的过滤行为,也不会改变 GROUP BY 的分组结果顺序(除非显式指定)**。真实执行顺序是:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT
。这意味着你在
ORDER BY
中引用的列,必须出现在
SELECT
列表中(SQL 标准模式下),或至少是
SELECT
中表达式可推导出的列。

排序实际发生在临时表或内存缓冲区中

MySQL 不会在磁盘表上直接排序,而是先将满足条件的行读入一个中间结构再排序:

如果结果集小且
sort_buffer_size
足够,全部在内存(
sort_buffer
)中完成快速排序
如果数据量超过
sort_buffer_size
,MySQL 会拆成多个块分别排序,写入磁盘临时文件,最后做归并排序(
Using filesort
若使用了覆盖索引且索引顺序匹配
ORDER BY
,可能跳过排序步骤,直接按索引物理顺序返回(
Using index

可通过

EXPLAIN
观察
Extra
字段是否含
Using filesort
来判断是否触发了额外排序开销。

ORDER BY + LIMIT 的优化关键在索引设计

当语句带

LIMIT
(如
ORDER BY created_at DESC LIMIT 20
),MySQL 仍需先排序全部符合条件的行,再取前 N 条——除非能用索引避免排序:

复合索引
(status, created_at)
可加速
WHERE status = 'active' ORDER BY created_at DESC
ORDER BY created_at DESC, id ASC
要求索引字段顺序和方向严格匹配,否则仍会
Using filesort
ORDER BY RAND()
无法走索引,必然全表扫描 + 内存排序,大数据量时极慢
EXPLAIN SELECT * FROM orders WHERE user_id = 123 ORDER BY paid_at DESC LIMIT 10;

若没在

(user_id, paid_at)
上建联合索引,即使
user_id
有单列索引,
ORDER BY
阶段仍大概率触发
filesort

NULL 值和 COLLATION 会影响排序结果一致性

MySQL 对

NULL
的排序位置默认是「最小值」(
ORDER BY col ASC
时排最前),但可通过
ORDER BY col IS NULL, col ASC
显式控制;字符类型还受
COLLATION
影响:

不同
COLLATION
(如
utf8mb4_0900_as_cs
vs
utf8mb4_general_ci
)会导致大小写、重音符号的比较逻辑不同
ORDER BY
列定义了
COLLATE
,优先级高于列默认值;否则继承列定义
跨表 JOIN 后
ORDER BY
多个字段,若字段
COLLATION
不一致,MySQL 可能报错
Illegal mix of collations

线上环境尤其要注意应用和数据库的

collation_connection
是否一致,否则同样 SQL 在不同会话中排序结果可能不一致。

排序不是“语法写在哪就哪执行”,它依赖执行计划、索引可用性、buffer 配置和字符规则——最常被忽略的是:

ORDER BY
的列没被索引覆盖,又没加
LIMIT
,此时哪怕只查 10 行,MySQL 也可能对百万行做完整排序。

相关推荐