6

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

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

查询 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   
4

5 回答 5

1

实际上,第一个查询的效率会降低(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。分组通常比连接更昂贵(在这种情况下可以将排除记录视为连接操作),因此它必须分组的记录越少,性能越好。

于 2011-06-23T16:34:36.660 回答
1

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

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

无论如何,我都会使用第二个版本,只是为了安全起见。


让我补充一点:

  • COUNT(*)通常比COUNT(notNullableField)MySQL 更有效。在未来的 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   
  • 在应用之前还有其他方法可以实现相同的 (to 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 种方法中哪一种更快取决于您的表大小和许多其他因素,因此最好使用您的数据进行测试。

于 2011-06-23T18:05:16.993 回答
0

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

于 2011-06-23T16:34:56.570 回答
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

希望这可以帮助。

于 2011-06-23T17:29:09.180 回答
-1

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

因为第一个查询将过滤来自 count(id) 条件的记录

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

第二个查询正确编写

于 2011-06-23T16:45:51.870 回答