HAVING和WHERE本质区别在于执行时机与作用对象:WHERE在分组前过滤原始行数据,不能用聚合函数;HAVING在GROUP BY后过滤分组结果,必须配合GROUP BY且可使用聚合函数。

HAVING 和 WHERE 看起来都是“加条件”,但它们根本不是同一阶段的过滤器——用错一个,结果可能对,性能却差几倍,甚至查不出想要的数据。
WHERE 是行级筛子,HAVING 是组级筛子
你写的每一条 SELECT 查询,MySQL 内部执行顺序固定:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY。这意味着:
-
WHERE在数据刚从磁盘读出来、还没分组时就动手——它看的是每一行原始值,比如WHERE status = 'active'或WHERE created_at > '2025-01-01' -
HAVING要等到GROUP BY完成、聚合函数(如COUNT()、SUM())算完才开始工作——它看的是每个分组的汇总结果,比如HAVING COUNT(*) > 5或HAVING AVG(price) > 100
所以别问“能不能把 WHERE 换成 HAVING”,先看你要过滤的是“单条记录”还是“一组记录的统计结果”。
WHERE 不能用聚合函数,HAVING 必须依赖 GROUP BY
这条限制不是语法糖,是执行流程决定的硬约束:
-
WHERE order_amount > 100✅ 合法——字段真实存在,且在聚合前就可取值 -
WHERE COUNT(*) > 10❌ 报错:Unknown column 'COUNT(*)' in 'where clause'——此时还没执行COUNT,压根没这个值 -
HAVING SUM(total) > 5000✅ 合法——前提是前面有GROUP BY user_id这类分组 -
HAVING total > 5000❌ 如果total不是GROUP BY列也不是聚合结果,会报错或行为不可靠
注意:HAVING 单独出现(无 GROUP BY)在 MySQL 中虽能运行(整张表当一个组),但属于非标准写法,其他数据库(如 PostgreSQL)直接拒绝,不建议依赖。
WHERE 过滤越早越好,HAVING 是不得已才用
性能差异不是理论——它直接影响扫描行数和内存占用:
- 写
WHERE product_type = 'electronics',MySQL 可能只读 1 万行就进分组;写成HAVING,就得先把 100 万行全读进来、全分组、全算完再筛 - 多表 JOIN 时更明显:
WHERE在 JOIN 前就砍掉无效行,HAVING得等 JOIN + GROUP BY 全做完才动手 - 别为了图方便把
WHERE条件全挪到HAVING——比如HAVING user_id IN (1,2,3) AND COUNT(*) > 1,前半段本该用WHERE
一个常被忽略的坑:WHERE 中的列名不能用 SELECT 别名,但 HAVING 可以——SELECT name AS n FROM t GROUP BY name HAVING n LIKE 'A%' 是合法的,而 WHERE n LIKE 'A%' 会报错。
HAVING 就容易变成慢查询的隐形推手。


















