having子句仅用于分组后过滤聚合结果,必须配合group by使用,且只能在where无法处理聚合条件(如having count(*)>10)时才合法使用;其性能不优于where,因where可提前减少分组数据量。

HAVING 子句本身从不比外层过滤(如 WHERE 或子查询)性能更好——它只是在特定逻辑下「不得不」用,且此时“外层过滤”根本不可行。
真正让人误以为 HAVING 更快的,是把“能用 WHERE 却没用好”和“必须用 HAVING”混为一谈了。
HAVING 的唯一合法使用场景:过滤聚合结果
HAVING 只能在 GROUP BY 后对已计算出的聚合值做判断,比如:
HAVING COUNT(*) > 10HAVING SUM(amount) >= 50000HAVING AVG(response_time) > 2000
这些条件在 WHERE 阶段根本无法计算,因为聚合函数还没执行。写 WHERE COUNT(*) > 10 会直接报错:Invalid use of group function。
所以这不是“选哪个更快”,而是“只能用 HAVING”。
为什么有人测出 HAVING 比子查询快?
那些所谓“HAVING 快 10 倍”的测试,往往踩了这几个坑:
- 把子查询写在
HAVING里(如HAVING SUM(x) > (SELECT ...)),导致该子查询被重复执行(每组一次),而正确做法应提至WITH或FROM子句中预计算 - 对比的“外层过滤”其实是嵌套两层
GROUP BY的派生表,做了两次全表扫描,而非单次分组 +HAVING - 测试数据量小、缓存干扰大,或没关查询缓存,把
HAVING查询命中 buffer pool 当成了“算法优势”
真实性能瓶颈永远在:哪一步减少的数据最多。WHERE 能筛掉 90% 行 → 分组成本骤降;HAVING 再怎么优化,也得先把全部分组做完。
HAVING 和外层 WHERE 组合才是常态
绝大多数高效查询都同时用两者:
-
WHERE过滤原始行(可走索引,如WHERE status = 'active' AND created_at >= '2026-01-01') -
GROUP BY分组 -
HAVING筛分组结果(如HAVING COUNT(*) >= 3 AND AVG(score) > 85)
漏掉 WHERE 预过滤,只靠 HAVING,等于让数据库白算一堆最终会被扔掉的组。
最常被忽略的一点:
有些数据库(如 MySQL 8.0)会对简单 HAVING 条件尝试下推,但这属于黑盒优化,不可验证、不可依赖;而 WHERE 是否走索引,用 EXPLAIN 一眼就能确认。











