MySQL Group By和HAVING

时间:2011-06-23 16:32:03

标签: mysql group-by having

我是一个MySQL查询noobie所以我确信这是一个明显答案的问题。

但是,我正在研究这两个问题。他们会返回不同的结果集吗?我理解排序过程会以不同的方式开始,但我相信它们会返回相同的结果,第一个查询的效率稍高一些吗?

查询1:HAVING,然后是AND

SELECT user_id   
FROM forum_posts  
GROUP BY user_id 
    HAVING COUNT(id) >= 100   
    AND user_id NOT IN (SELECT user_id FROM banned_users)

查询2:WHERE,然后HAVING

SELECT user_id   
FROM forum_posts 
WHERE user_id NOT IN(SELECT user_id FROM banned_users) 
GROUP BY user_id 
    HAVING COUNT(id) >= 100   

5 个答案:

答案 0 :(得分:2)

实际上,第一个查询的效率会降低(HAVING之后应用WHERE) 的更新

一些伪代码,用于说明查询的执行方式([非常]简化版本)  第一个问题:
1. SELECT user_id FROM forum_posts
2. SELECT user_id FROM banned_user
3.团体,计数等。
4.如果第一个结果集中的记录显示在第二个

中,则将其排除

第二次查询
1. SELECT user_id FROM forum_posts
2. SELECT user_id FROM banned_user
3.如果第一个结果集中的记录显示在第二个结果集中,则将其排除 4.分组,计数等。

步骤1,2的顺序并不重要,mysql可以选择它认为更好的任何东西。重要的区别在于步骤3,4。在GROUP BY之后应用。分组通常比加入更昂贵(在这种情况下不包括记录可以考虑作为连接操作),因此分组记录越少,性能就越好。

答案 1 :(得分:0)

HAVING条件应用于分组结果,并且由于您按user_id分组,因此所有可能的值都将出现在分组结果中,因此放置user_id条件并不重要

答案 2 :(得分:0)

对我来说,第二个查询更有效率,因为它会降低GROUP BY和HAVING的记录数。

或者,您可以尝试以下查询以避免使用IN:

SELECT `fp`.`user_id`
FROM `forum_posts` `fp`
LEFT JOIN `banned_users` `bu` ON `fp`.`user_id` = `bu`.`user_id`
WHERE `bu`.`user_id` IS NULL
GROUP BY `fp`.`user_id`
HAVING COUNT(`fp`.`id`) >= 100

希望这有帮助。

答案 3 :(得分:0)

您已经回答两个查询将显示相同的结果以及各种更有效的意见。

我的意见是,效率差异(速度),只有优化器才会产生不同的计划 2查询。我认为对于最新的MySQL版本,优化器足够聪明,可以为任一查询找到相同的计划,因此根本没有区别但是当然可以测试并查看EXPLAIN的执行计划或针对某些测试表运行2个查询。

我会在任何情况下使用第二个版本,只是为了安全起见。


让我补充一点:

  • COUNT(*)通常比MySQL中的COUNT(notNullableField)更有效。在未来的MySQL版本中修复之前,请在适用的地方使用COUNT(*)

因此,您也可以使用:

SELECT user_id   
FROM forum_posts 
WHERE user_id NOT IN
  ( SELECT user_id FROM banned_users ) 
GROUP BY user_id 
HAVING COUNT(*) >= 100   
  • 在应用NOT IN之前,还有其他方法可以实现相同(到GROUP BY)子结果。

使用LEFT JOIN / NULL

SELECT fp.user_id   
FROM forum_posts AS fp
  LEFT JOIN banned_users AS bu
    ON bu.user_id = fp.user_id
WHERE bu.user_id IS NULL 
GROUP BY fp.user_id 
HAVING COUNT(*) >= 100  

使用NOT EXISTS

SELECT fp.user_id   
FROM forum_posts AS fp 
WHERE NOT EXISTS
  ( SELECT * 
    FROM banned_users AS bu
    WHERE bu.user_id = fp.user_id
  ) 
GROUP BY fp.user_id 
HAVING COUNT(*) >= 100   

3种方法中哪一种更快取决于您的表格大小和许多其他因素,因此最好使用您的数据进行测试。

答案 4 :(得分:-1)

不,它没有给出相同的结果。

因为第一个查询将从count(id)条件

中过滤记录

另一个查询过滤器记录然后应用having子句。

正确编写第二个查询