MySQL SQL 语句执行顺序详解
MySQL 执行 SQL 语句时,并不是按照代码的书写顺序执行的,而是遵循一套固定的逻辑流程。理解执行顺序对于编写高效 SQL、排查查询问题至关重要。
完整执行顺序
MySQL 对 SQL 语句的执行顺序如下(按序号依次执行):
FROM及关联操作- 首先确定查询的数据源,包括主表(
FROM <left_table>)和关联表(<join_type> JOIN <right_table>)。 - 通过
ON <join_condition>过滤关联条件,生成临时数据集(包含两表匹配的记录)。
- 首先确定查询的数据源,包括主表(
WHERE过滤- 对
FROM阶段生成的临时数据集进行行级过滤,仅保留满足<where_condition>的记录。 - 注意:此时还不能使用
SELECT中定义的别名,也不能使用聚合函数(如SUM()、COUNT())。
- 对
GROUP BY分组- 按
<group_by_list>指定的字段对数据进行分组,相同分组的记录会被合并为一行。 - 分组后,后续操作(如
HAVING、SELECT)只能针对分组后的结果进行处理。
- 按
HAVING过滤- 对
GROUP BY分组后的结果进行过滤,仅保留满足<having_condition>的分组。 - 与
WHERE的区别:HAVING可使用聚合函数(如HAVING COUNT(*) > 10),而WHERE不行。
- 对
SELECT字段筛选- 从前面的结果集中筛选出
<select_list>指定的字段或计算结果(如SELECT name, age+1 AS new_age)。 - 此时可以使用别名(如
new_age)。
- 从前面的结果集中筛选出
DISTINCT去重- 对
SELECT阶段的结果进行去重,保留唯一的记录。
- 对
ORDER BY排序- 按
<order_by_condition>对结果集进行排序(如ORDER BY age DESC)。 - 可以使用
SELECT中定义的别名(如ORDER BY new_age)。
- 按
LIMIT限制结果- 按
<limit_number>截取结果集的前 N 行(如LIMIT 10取前 10 行,LIMIT 5,10从第 5 行开始取 10 行)。
- 按
关键阶段解析
1. FROM 与 JOIN 阶段
- 先加载主表和关联表的数据,通过
ON条件筛选匹配的记录(而非WHERE)。 - 例:
SELECT * FROM a JOIN b ON a.id = b.a_id WHERE a.status = 1中,ON先筛选两表关联关系,再通过WHERE过滤主表状态。
2. WHERE 与 HAVING 的区别
| 特性 | WHERE |
HAVING |
|---|---|---|
| 执行阶段 | GROUP BY 之前 |
GROUP BY 之后 |
| 作用对象 | 原始行数据 | 分组后的结果 |
| 支持聚合函数 | 不支持(如 COUNT()) |
支持(如 COUNT(*) > 5) |
| 支持别名 | 不支持(SELECT 未执行) |
支持(SELECT 已执行) |
3. ORDER BY 的特殊性
- 排序操作在
SELECT之后,因此可以使用SELECT中定义的别名(如SELECT age AS a ORDER BY a)。 - 若未使用索引排序,会触发
Using filesort(文件排序),可能影响性能。
示例验证
以下 SQL 的执行流程:
1 | SELECT |
FROM+JOIN+ON:关联employee和dept表,通过employee.dept_id = dept.id匹配记录。WHERE:筛选出 2020 年后入职的员工(hire_year > 2020)。GROUP BY:按department字段分组。HAVING:保留平均工资大于 10000 的部门(avg_salary > 10000)。SELECT:提取department和平均工资(avg_salary)。ORDER BY:按avg_salary降序排序。LIMIT:取前 3 条结果