SQL 的执行顺序通常为:from->join->where->group by->having->select->order by->limit。
一、SQL关键字的实际执行顺序
-
FROM
和JOIN
(含ON
条件)-
作用:确定数据来源表,执行表连接操作并应用连接条件(如
ON users.id = orders.user_id
)。 -
执行逻辑:首先生成原始数据集(笛卡尔积),再根据连接条件筛选有效数据。
-
-
WHERE
-
作用:过滤行级数据,排除不满足条件的记录。
-
限制:不可使用聚合函数(如COUNT,SUM),因为分组尚未发生。
-
示例:
WHERE hire_date > '2020-01-01'
。
-
-
GROUP BY
-
作用:按指定列分组数据,为聚合计算做准备。
-
注意:SELECT中的非聚合列必须出现在GROUP BY中。
-
-
HAVING
-
作用:过滤分组后的数据,可使用聚合函数。
-
与WHERE区别:WHERE在分组前过滤行,HAVING在分组后过滤组。
-
示例:
HAVING COUNT(*) > 5
。
-
-
SELECT
-
作用:选择最终返回的列,计算表达式或聚合值(如
AVG(salary)
),并定义别名。 -
关键点:此时生成的列别名(如avg_salary)可被后续
ORDER BY
使用,但不可用于WHERE
或GROUP BY
(因二者先于SELECT执行)。
-
-
DISTINCT
-
作用:对 SELECT 的结果去重(若有 DISTINCT关键字)。
-
-
ORDER BY
-
作用:按指定列排序结果集,可使用
SELECT
中的别名。 -
示例:ORDER BY avg_salary DESC。
-
-
LIMIT
/OFFSET
-
作用:限制返回行数或跳过指定行,最后执行。
-
二、常见误区与原理分析
-
WHERE
与HAVING
混淆-
错误示例:
SELECT department, AVG(salary) AS avg_salary FROM employees WHERE avg_salary > 10000 -- 错误!WHERE不能使用别名或聚合函数 GROUP BY department;
-
修正:将条件移至HAVING:HAVING AVG(salary) > 10000。
-
-
别名使用范围
-
SELECT
别名仅在ORDER BY
和LIMIT
中生效,在 WHERE 、GROUP BY、HAVING中无效(因执行顺序优先)。
-
-
性能优化原则
-
尽早过滤数据:在 WHERE 中尽量缩小数据集,减少后续分组和排序的计算量。
-
避免冗余操作:不必要的 GROUP BY 或复杂 HAVING 条件会显著降低效率。
-
三、执行顺序对比表
关键字 | 书写顺序 | 执行顺序 | 可用聚合函数 | 可用SELECT别名 |
---|---|---|---|---|
FROM / JOIN | 2 | 1 | ❌ | ❌ |
WHERE | 3 | 2 | ❌ | ❌ |
GROUP BY | 4 | 3 | ❌ | ❌ |
HAVING | 5 | 4 | ✔️ | ❌ |
SELECT | 1 | 5 | ✔️ | ❌(自身定义) |
ORDER BY | 6 | 7 | ✔️ | ✔️ |
LIMIT | 7 | 8 | ❌ | ✔️ |
四、完整示例解析
SELECT department, COUNT(*) AS emp_count -- 5. 选择字段并定义别名
FROM employees e
JOIN departments d ON e.dept_id = d.id -- 1. 连接表
WHERE e.hire_date > '2020-01-01' -- 2. 过滤入职时间
GROUP BY department -- 3. 按部门分组
HAVING COUNT(*) > 5 -- 4. 过滤分组(员工数>5)
ORDER BY emp_count DESC -- 6. 按别名排序
LIMIT 3; -- 7. 限制结果数
总结
SQL引擎的实际执行顺序固定为: FROM
→ JOIN
→ WHERE
→ GROUP BY
→ HAVING
→ SELECT
→ DISTINCT
→ ORDER BY
→ LIMIT
掌握该顺序可避免逻辑错误(如别名/聚合函数误用),并提升查询性能。建议通过EXPLAIN
命令进一步分析具体数据库的执行计划优化细节。