SQL执行顺序为FROM→WHERE→GROUP BY→HAVING→SELECT→ORDER BY;WHERE过滤原始行,HAVING过滤分组后结果,聚合函数仅在HAVING中合法使用。

WHERE 在 GROUP BY 之前执行,HAVING 在之后
SQL 的逻辑执行顺序是硬性流程:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。这个顺序不是语法书写顺序,而是数据库引擎处理数据的真实链条。WHERE 看到的是原始表里每一行;HAVING 看到的是已经分好组、且每个组的 COUNT(*)、SUM() 等值都算出来的结果集。
WHERE 过滤行,HAVING 过滤组
这是执行顺序差异带来的直接后果:
-
WHERE status = 'active'会把所有非 active 行直接丢弃,这些行不会参与任何分组或聚合计算 -
HAVING COUNT(*) > 5不管组里每条记录是什么,只要该组最终计数 ≤ 5,整组就从结果中消失 - 误把
WHERE order_date >= '2026-01-01'写成HAVING,会导致数据库先对全部年份的数据分组求和,再扔掉 2026 年之前的组——算都算完了才筛,纯属浪费
聚合函数只能在 HAVING 中合法使用
不是语法限制,而是逻辑必然:COUNT(*) 需要多行才能得出一个值,而 WHERE 处理的是单行,此时聚合结果根本不存在。
- ✅
WHERE salary > 5000:字段来自原表,有效 - ❌
WHERE AVG(salary) > 8000:报错,AVG尚未计算 - ✅
GROUP BY dept HAVING AVG(salary) > 8000:分组完成,每组平均值已知 - ⚠️
HAVING hire_date > '2020-01-01':除非hire_date出现在GROUP BY中,否则多数数据库会报错或返回空
没有“HAVING 更快”的场景,只有“写错位置导致误判”
所谓 HAVING 查询更快,基本都源于干扰项:
- 对比时一方命中查询缓存,另一方没命中,把缓存效应当成子句优势
- 用
HAVING COUNT(*) > 1查小表,看不出延迟,就以为它“不慢” -
WHERE写在GROUP BY后面导致语法错误,换成HAVING后能执行,误以为是优化 - 真正影响速度的是数据落点:早过滤(
WHERE)减少输入量,晚过滤(HAVING)只减少输出量——中间所有聚合计算照做不误
最容易被忽略的一点:有些新版数据库(如 MySQL 8.0)会对简单 HAVING 条件尝试下推,但这属于不可控的内部优化;而 WHERE 走索引是稳定、可 EXPLAIN 验证的行为。

















