14

以下两个查询产生完全相同的结果:

select country, count(organization) as N
from ismember
group by country
having N > 50;

select * from (
  select country, count(organization) as N
  from ismember
  group by country) x
where N > 50;

每个HAVING子句都可以用子查询和WHERE这样的子句代替吗?或者在某些情况下,一个HAVING子句是绝对必要的/更强大/更有效/无论如何?

4

6 回答 6

11

这里有 2 个问题: 第一个问题的答案是肯定的:HAVING-laden 查询的结果集与作为子查询执行的相同查询的结果集相同,并用WHERE子句装饰。

第二个问题是关于性能和表现力的——我们在这里深入实施。在 MySQL 上,有一条细红线,性能开始偏离:内部查询的结果集不能再保存在内存中的那一刻。在这种情况下,MySQL 将创建内部查询的磁盘表示,然后在其上使用WHERE选择器。这不会发生,如果HAVING使用该子句,则不合格的组将从结果集中删除。

这意味着,子句的选择性越高,HAVING它的性能相关性就越大:考虑内部查询的一百万行的结果集,即通过HAVING子句减少到 5 行 - 结果集很可能内部查询的一部分不会保存在内存中,但很可能最终结果集会保存。

编辑

我曾经遇到过这样的情况:查询从一个分布非常均匀的表中选择了几个异常值(每天在车间的物理机器上生产的件数)。由于 IO 负载高,我进行了调查。

编辑 2

请记住,查询缓存用于子查询 - 恕我直言,地方开发应该更多地关注 - 所以子查询模式不会从内部查询作为缓存结果集中受益。

于 2012-08-25T10:32:19.110 回答
9

在 Sql Server 2008 中,两个类似的查询具有完全相同的执行计划:

在此处输入图像描述

我还研究了许多由 Entity Framework(使用 SS 2008)生成的查询,到目前为止,我从未见过带有HAVING子句的查询。对聚合结果带有条件的分组查询总是被转换为带有子查询的查询。我相信 ADO.Net 团队知道他们在做什么......

于 2012-08-25T10:41:04.063 回答
4

HAVING 子句对于避免增加子查询的复杂性非常有用。但是,这两者在逻辑上是等价的,并且每个 HAVING 子句都可以像您一样使用子查询重写。

如果您很好奇,如果您准备将 GROUP BY 发挥到极致,您还可以将每个 WHERE 子句编写为 HAVING 子句。

于 2012-08-25T10:34:23.713 回答
1

我知道,您将其从一般更改为 MySQL,但我想在这里添加一个(可能有用的)注释。稍作修改后,我在 SQL Server 2008 中尝试了您的查询。

对于任何想要了解更多细节的人来说,这两个查询的执行计划在 SQL Server 2008 中甚至完全相同。因此优化器以相同的方式处理这两个命令,具有相同的性能和估计。

于 2012-08-25T10:41:22.520 回答
0

逻辑上是的,结果最终将是相同的。但性能可能会有所不同。HAVING 子句可能会导致数据库更改不同的执行计划。

给上面的人的说明(不能以某种方式直接评论)-执行计划不仅取决于您的查询。它也可能由数据库根据统计数据进行调整,例如运行时的表大小等。至少对于 DB2 来说...

于 2012-08-25T14:36:11.833 回答
0

恕我直言,使用该HAVING子句应该是有效的,因为在第二种情况下,将在包含运行过滤条件的分组结果的工作表上进行额外的传递。

于 2012-08-25T10:27:11.733 回答