SQL 逻辑处理顺序详解
SQL 逻辑处理顺序详解
一、SQL 语句的逻辑处理顺序概述
SQL 语句的实际执行顺序与书写顺序不同,理解这个逻辑处理顺序是写出高效查询的关键。以下是完整的逻辑处理阶段:
关键结论:SQL 执行顺序是
FROM → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT/OFFSET
,这个顺序决定了各子句如何相互影响。
go专栏:https://duoke360.com/tutorial/path/golang
二、各阶段详细解析
1. FROM 和 JOIN 阶段
- FROM 子句首先执行,确定数据来源
- JOIN 操作在此阶段处理(包括 INNER/LEFT/RIGHT/FULL JOIN)
- 生成中间结果集(笛卡尔积或连接后的数据集)
-- 示例:先处理FROM和JOIN
FROM employees e
JOIN departments d ON e.dept_id = d.id
2. WHERE 阶段
- 对 FROM 生成的中间结果应用过滤条件
- 不可使用 SELECT 中定义的别名
- 高效 WHERE 应尽量减少行数
优化提示:WHERE 条件中优先使用索引列,且将高选择性条件放在前面。
3. GROUP BY 阶段
- 按照指定列分组聚合
- 非聚合列必须出现在 GROUP BY 中
- 生成分组后的中间结果
-- GROUP BY 处理示例
GROUP BY department_id
4. HAVING 阶段
- 对分组后的结果进行过滤
- 可引用聚合函数(如 HAVING SUM(salary) > 100000)
- 比 WHERE 晚执行,应尽量用 WHERE 提前过滤
5. SELECT 阶段
- 此时才计算选择列表中的表达式
- 可创建列别名(后续阶段可用)
- 处理聚合函数(如 SUM/AVG)
-- SELECT 处理示例
SELECT department_id, AVG(salary) as avg_salary
6. DISTINCT 阶段
- 去除重复行
- 性能消耗大,谨慎使用
- 在 SELECT 之后执行
7. ORDER BY 阶段
- 对最终结果排序
- 可使用 SELECT 中的别名
- 对于大结果集可能很昂贵
-- ORDER BY 处理示例
ORDER BY avg_salary DESC
8. LIMIT/OFFSET 阶段
- 最后应用分页操作
- 在排序后执行,保证返回正确的记录
- 注意 OFFSET 可能导致性能问题
三、高级应用场景
1. 子查询的处理顺序
- FROM 子查询:最先执行,作为数据源
- WHERE 子查询:在 WHERE 阶段执行
- SELECT 子查询:在 SELECT 阶段为每行执行
2. 窗口函数的特殊处理
窗口函数在 SELECT 和 ORDER BY 之间执行:
- 先处理 FROM/WHERE/GROUP BY/HAVING
- 然后执行窗口函数计算
- 最后应用 ORDER BY/LIMIT
SELECT employee_id,salary,RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) as rank
FROM employees
3. CTE (WITH 子句) 的处理
- 递归 CTE 有特殊处理流程
- 非递归 CTE 在 FROM 前物化
- 可看作临时视图
四、面试常见问题
1. WHERE 和 HAVING 的区别?
答案:WHERE 在分组前过滤行,HAVING 在分组后过滤组。WHERE 不能使用聚合函数,HAVING 可以。
2. 以下查询的执行顺序?
SELECT dept_id, AVG(salary) as avg_sal
FROM employees
WHERE hire_date > '2020-01-01'
GROUP BY dept_id
HAVING AVG(salary) > 5000
ORDER BY avg_sal DESC
LIMIT 10;
执行顺序:
- FROM employees
- WHERE hire_date > ‘2020-01-01’
- GROUP BY dept_id
- HAVING AVG(salary) > 5000
- SELECT dept_id, AVG(salary) as avg_sal
- ORDER BY avg_sal DESC
- LIMIT 10
3. 为什么不能在 WHERE 中使用列别名?
因为 WHERE 在 SELECT 之前执行,此时别名尚未定义。
五、性能优化建议
- 尽早过滤:在 WHERE 中尽量减少行数
- 减少排序:ORDER BY 和 DISTINCT 很昂贵
- 合理使用索引:确保 WHERE/JOIN 条件使用索引
- **避免 SELECT ***:只选择需要的列
- 注意 JOIN 顺序:小表驱动大表
理解 SQL 的逻辑处理顺序不仅能帮助写出正确的查询,更是性能优化的基础。在面试中展示这种深层次理解会给面试官留下深刻印象。