Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL分组并具有_Mysql_Group By_Having - Fatal编程技术网

MySQL分组并具有

MySQL分组并具有,mysql,group-by,having,Mysql,Group By,Having,我是MySQL查询高手,所以我相信这是一个答案显而易见的问题 但是,我在看这两个问题。它们会返回不同的结果集吗?我知道排序过程将以不同的方式开始,但我相信它们将返回相同的结果,而第一次查询的效率会稍高一些 问题1:拥有、然后和 SELECT user_id FROM forum_posts GROUP BY user_id HAVING COUNT(id) >= 100 AND user_id NOT IN (SELECT user_id FROM ban

我是MySQL查询高手,所以我相信这是一个答案显而易见的问题

但是,我在看这两个问题。它们会返回不同的结果集吗?我知道排序过程将以不同的方式开始,但我相信它们将返回相同的结果,而第一次查询的效率会稍高一些

问题1:拥有、然后和

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:在哪里,然后有

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   

实际上,第一个查询的效率较低(
WHERE
之后应用了
)。
更新

一些伪代码说明如何执行查询([非常]简化的版本)。
第一个查询:
1. <代码>从论坛帖子中选择用户id

2. <代码>从禁用用户中选择用户id

3.分组、计数等
4.从第一个结果集中排除记录(如果记录在第二个结果集中)

第二次查询
1. <代码>从论坛帖子中选择用户id
2. <代码>从禁用用户中选择用户id
3.如果记录在第二个结果集中,则从第一个结果集中排除这些记录
4.分组、计数等


步骤1、2的顺序并不重要,mysql可以选择它认为更好的。重要的区别在于步骤3、4。在
分组后应用have。分组通常比加入更昂贵(在这种情况下,排除记录可被视为加入操作),因此它必须分组的记录越少,性能越好。

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

不,它不会给出相同的结果

因为第一个查询将从计数(id)条件中筛选记录

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


第二次查询写得正确

对我来说,第二次查询效率更高,因为它减少了GROUP BY和HAVING的记录数

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

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

希望这会有所帮助。

您已经回答了这两个查询将显示相同的结果和不同的意见,其中一个更有效

我的观点是,只有当优化器为这两个查询提供不同的计划时,效率(速度)才会有差异。我认为,对于最新的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   
  • 在应用
    分组方式之前,还有其他方法可以实现相同的子结果(不在
    中)
使用
左连接/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  
使用
不存在

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种方法中哪一种更快取决于您的表大小和许多其他因素,因此最好使用您的数据进行测试。

太好了,谢谢!有趣的是,我得做一些测试。我认为这样会更有效率,因为在分组后,比较非被禁止用户部分的记录比以前少了?如果这有意义的话。是的,该条件将仅针对分组结果进行测试,而不是全部,在分组之前。@kimmothy:NOT in
中的子查询实际上只需要执行一次。我添加了一个更新来说明两个查询之间的差异。@a1ex07:您确定实际执行计划中有差异吗?因为您说结果会不同,在你知道解决了什么问题之前,你很难断言哪一个写得正确。至少,它们在语法上都是正确的。事实上,结果也是一样的。这是他们在效率上的不同。@Andrey:你确定效率上有差异吗?@ypercube:我希望在WHERE之后,甚至在GROUP BY之后(我认为,这也是在WHERE之后计算的)进行评估。因此,第一个查询将不必要地计算稍后将根据
user\u id
丢弃的行的计数。第二个是在聚合之前过滤掉
user\u id
。放置很重要。如果应用了
中的,则分组的行数更少(甚至为零),因此必须仅为这些行计算COUNT()。如果留给
HAVING
子句,则对所有行进行分组(和计数),然后检查条件。结果:如果被禁止的用户占所有用户的很大比例,那么速度的差异将是巨大的(成比例的)。当然,只有当优化器对这两个查询有不同的计划时,速度的差异才会存在。感谢您指出这一点,我从这里的答案中学到了很多。:)