通常,如果没有having
子句(特别是MySQL,PostrgrSQL,Oracle和MSSQL),where
和group by
子句之间是否有任何区别?
select * from user where foo > 3
似乎相当于
select * from user having foo > 3
答案 0 :(得分:3)
至少有一个巨大差异:
HAVING
子句不使用索引:
explain select username from users having user_id = 32654456;
+----+-------------+--------+-------+---------------+---------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+--------+-------------+
| 1 | SIMPLE | users | index | NULL | PRIMARY | 32 | NULL | 661107 | Using index |
+----+-------------+--------+-------+---------------+---------+---------+------+--------+-------------+
虽然WHERE
子句将:
explain select username from users where user_id = 32654456;
+----+-------------+--------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | users | const | PRIMARY | PRIMARY | 32 | const | 1 | Using index |
+----+-------------+--------+-------+---------------+---------+---------+-------+------+-------------+
答案 1 :(得分:3)
这是文档在SELECT
statement页面上所说的内容:
HAVING
子句几乎在最后一次应用,就在项目发送到客户端之前,没有优化。 (LIMIT
后会应用HAVING
。)SQL标准要求
HAVING
必须仅引用GROUP BY
子句中的列或聚合函数中使用的列。但是,MySQL支持对此行为的扩展,并允许HAVING
引用SELECT
列表中的列和外部子查询中的列。请勿将
HAVING
用于WHERE
子句中的项目。例如,不要写下以下内容:SELECT col_name FROM tbl_name HAVING col_name > 0
改为写下:
SELECT col_name FROM tbl_name WHERE col_name > 0
HAVING
子句可以引用聚合函数,WHERE
子句不能:SELECT user, MAX(salary) FROM users GROUP BY user HAVING MAX(salary) > 10
此外,在optimization of WHERE
clauses页面上:
MySQL执行的一些优化如下:
如果您不使用
HAVING
或汇总功能(WHERE
,GROUP BY
等),则
COUNT()
与MIN()
合并。 1在输出每一行之前,将跳过与
HAVING
子句不匹配的行。
1 一些测试显示HAVING
合并到WHERE
(当上述条件适用时)并不会使这些条款等效。使用EXPLAIN
语句显示未使用HAVING
子句中列的索引。
另请阅读@ tudor-constantin的answer及其产生的讨论。
工作原理
HAVING
子句在结束时处理,就在结果集发送回客户端之前,而WHERE
子句在查询执行的早期处理。
当查询JOIN
有两个或更多表时,它会产生很大的不同。使用第二个表中的列的不匹配WHERE
条件会停止从第二个表和下一个表中检索数据,但是当它保留在HAVING
子句中时,它会让数据检索继续并丢弃经过大量的努力才得到它。
使用单个表的查询也存在差异:HAVING
子句中的列上的索引不用于过滤从表中读取的行。索引用于过滤从表中读取的行(有时索引甚至可以完全抑制表数据的读取)和排序。不使用索引会导致查询速度变慢。
WHERE
和HAVING
条款不相同。即使它们产生相同的最终结果,查询的执行方式也会有很大差异。
放入HAVING
子句中可以保留在WHERE
子句中的条件(见上文)会造成资源浪费(CPU处理能力,数据存储访问,时间)。
答案 2 :(得分:2)
另一个差异...别名由HAVING
识别,但不识别WHERE
:
mysql> SELECT city AS c FROM Canada WHERE c='Toronto';
ERROR 1054 (42S22): Unknown column 'c' in 'where clause'
mysql> SELECT city AS c FROM Canada HAVING c='Toronto';
+---------+
| c |
+---------+
| Toronto |
+---------+
(进一步检查表明,HAVING
时WHERE
未使用索引。版本5.6.12。)