Administrator
Published on 2025-03-10 / 8 Visits
0
0

SQL 中 select、from、join、where、group by、having、order by、limit 的执行顺序

在 SQL 中,虽然查询的 书写顺序SELECT → FROM → JOIN → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT,但数据库引擎的 实际执行顺序 完全不同。理解执行顺序对编写高效查询和排查问题至关重要。以下是完整的执行顺序及关键逻辑:


SQL 执行顺序详解

**1. FROM + JOIN

  • 作用:确定数据来源,加载表并处理表连接(如 INNER JOIN, LEFT JOIN)。
  • 逻辑
    • 先执行 FROM 子句,确定主表。
    • 根据 JOIN 条件连接其他表(生成笛卡尔积后按条件筛选)。
  • 示例
    FROM tableA 
    LEFT JOIN tableB ON tableA.id = tableB.a_id
    

**2. WHERE

  • 作用:对 FROMJOIN 后的中间结果进行行级过滤。
  • 注意
    • 无法使用聚合函数(如 SUM()),因为此时尚未分组。
    • 过滤越早,后续处理的数据量越小,性能越高。
  • 示例
    WHERE tableA.age > 18
    

**3. GROUP BY

  • 作用:将数据按指定列分组,为聚合函数(如 COUNT(), SUM())做准备。
  • 逻辑
    • 若未指定 GROUP BY,整张表视为一个组。
    • 分组后,每组只保留一行结果。
  • 示例
    GROUP BY tableA.department
    

**4. HAVING

  • 作用:对分组后的结果进行过滤(类似 WHERE,但作用于组)。
  • 注意
    • 可使用聚合函数(如 HAVING SUM(sales) > 1000)。
    • 必须在 GROUP BY 之后执行。
  • 示例
    HAVING AVG(salary) > 5000
    

**5. SELECT

  • 作用:选择最终输出的列,并计算表达式或聚合函数。
  • 关键点
    • 别名(如 AS total)在此阶段生成,后续步骤(如 ORDER BY)可使用别名。
    • SELECT * 在此阶段展开为具体列。
  • 示例
    SELECT department, AVG(salary) AS avg_salary
    

**6. DISTINCT

  • 作用:去重(若指定了 DISTINCT)。
  • 逻辑
    • SELECT 之后执行,对最终结果去重。
  • 示例
    SELECT DISTINCT department
    

**7. ORDER BY

  • 作用:对结果排序。
  • 注意
    • 可使用 SELECT 中的别名(如 avg_salary)。
    • 排序是性能瓶颈,应尽量减少排序数据量。
  • 示例
    ORDER BY avg_salary DESC
    

**8. LIMIT / OFFSET

  • 作用:限制返回的行数或分页。
  • 逻辑
    • 在最终结果上截取指定行。
    • 分页时注意性能问题(如 LIMIT 100000, 10 会遍历前 100010 行)。
  • 示例
    LIMIT 10
    

执行顺序总结

执行顺序: 
FROMJOINWHEREGROUP BYHAVINGSELECTDISTINCTORDER BY → LIMIT

示例分析

SELECT 
    department, 
    AVG(salary) AS avg_salary   -- 5. 计算平均工资并命名
FROM employees                  -- 1. 从 employees 表加载数据
LEFT JOIN departments ON ...    -- 1. 连接 departments 表
WHERE hire_date > '2020-01-01'  -- 2. 过滤入职时间
GROUP BY department             -- 3. 按部门分组
HAVING AVG(salary) > 5000      -- 4. 过滤平均工资低的组
ORDER BY avg_salary DESC        -- 7. 按平均工资排序
LIMIT 10;                       -- 8. 返回前 10 条

常见误区与优化建议

  1. WHERE vs HAVING

    • WHERE 在分组前过滤行,HAVING 在分组后过滤组。
    • 尽量用 WHERE 提前减少数据量,避免 HAVING 处理大量分组。
  2. 别名使用

    • GROUP BYHAVING 不能使用 SELECT 中的别名(因为执行顺序在前)。
    • ORDER BY 可以使用别名。
  3. 性能优化

    • WHEREJOIN 条件中尽量使用索引。
    • 避免在 SELECTWHERE 中写复杂表达式(可提前计算)。

执行顺序对结果的影响

  • 错误示例
    SELECT 
        department, 
        AVG(salary) AS avg_salary
    FROM employees
    WHERE avg_salary > 5000  -- 错误!WHERE 不能使用 SELECT 的别名
    GROUP BY department;
    
    • 正确写法应使用 HAVING AVG(salary) > 5000


Comment