是"有"和"其中"完全等同于没有" group by"条款?

时间:2016-05-01 05:27:33

标签: mysql sql database performance syntax

通常,如果没有having子句(特别是MySQL,PostrgrSQL,Oracle和MSSQL),wheregroup by子句之间是否有任何区别?

select * from user where foo > 3 似乎相当于 select * from user having foo > 3

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或汇总功能(WHEREGROUP BY等),则
  • COUNT()MIN()合并。 1

  •   
  • 在输出每一行之前,将跳过与HAVING子句不匹配的行。

  •   

1 一些测试显示HAVING合并到WHERE(当上述条件适用时)并不会使这些条款等效。使用EXPLAIN语句显示未使用HAVING子句中列的索引。

另请阅读@ tudor-constantin的answer及其产生的讨论。

工作原理

HAVING子句在结束时处理,就在结果集发送回客户端之前,而WHERE子句在查询执行的早期处理。

当查询JOIN有两个或更多表时,它会产生很大的不同。使用第二个表中的列的不匹配WHERE条件会停止从第二个表和下一个表中检索数据,但是当它保留在HAVING子句中时,它会让数据检索继续并丢弃经过大量的努力才得到它。

使用单个表的查询也存在差异:HAVING子句中的列上的索引不用于过滤从表中读取的行。索引用于过滤从表中读取的行(有时索引甚至可以完全抑制表数据的读取)和排序。不使用索引会导致查询速度变慢。

最终决议

WHEREHAVING条款不相同。即使它们产生相同的最终结果,查询的执行方式也会有很大差异。

放入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 |
+---------+

(进一步检查表明,HAVINGWHERE未使用索引。版本5.6.12。)