HAVING 和 SELECT 中的计算是否意味着它将执行两次?

Pet*_*ter 5 sql sql-server group-by

假设我有这个查询:

SELECT CompanyId, COUNT(*) as Total
FROM Customer
GROUP BY CompanyId
HAVING COUNT(*) > 100
Run Code Online (Sandbox Code Playgroud)

COUNT(*)我的查询中有两次。这是否意味着COUNT执行了两次?

这是一个简单的示例,但是当我进行更复杂的计算(例如SUM(Weight) / COUNT(*))时,我担心它可能会影响性能。或者任何性能影响都可以忽略不计?

我正在使用 MS SQL 2012,并且无法执行HAVING Total > 100.

Jer*_*ert 7

如果您对查询的幕后处理方式非常感兴趣,请熟悉执行计划以及如何阅读它们。以下所有内容都是使用这些内容通过实验建立的。

聚合不会计算多次,但涉及聚合的表达式却会计算多次。考虑:

SELECT CompanyId, SUM(Weight) / COUNT(*)
FROM Customer
GROUP BY CompanyId
HAVING SUM(Weight) / COUNT(*) > 100
Run Code Online (Sandbox Code Playgroud)

SUM(Weight)并且COUNT(*)只会计算一次,但除法将执行两次(一次在过滤时,一次在选择时)。当然,这对性能没有可衡量的影响——关键是它最大限度地减少了必须检查所有数据的次数。

这意味着即使您的列表HAVING与您的列表完全不同SELECT,该表仍然只会被扫描一次并聚合一次:

SELECT CompanyId, MAX(Weight), MIN(Weight), COUNT(*) as Total
FROM Customer
GROUP BY CompanyId
HAVING MAX(Weight) > 2 * MIN(Weight) AND AVG(Weight) > 0.5
Run Code Online (Sandbox Code Playgroud)

这里有四个聚合:MAX(Weight)MIN(Weight)和。1优化器将一次性计算所有这些,按 分组,应用过滤器,然后选择所需的结果。2AVG(Weight)COUNT(*)CompanyIdHAVING

免责声明:与有关优化器功能的所有声明一样,所有这些都可能在 SQL Server 的任何版本中发生更改,并且可能会因跟踪标志、统计信息、索引和特定查询的具体情况而异。上述情况对于 SQL Server 2012 和 2016 来说是正确的,至少对于两个特定的数据库来说是这样,其中索引不起作用。


  1. AVG实际上它本身并不是一个聚合体;在内部,优化器将其扩展为SUM / COUNT(*),并进行检查以防止被零除。所以聚合实际上是MAXMINSUMCOUNT
  2. 这是顺序计划的情况。对于并行计划,由于必须将多个并行扫描连接在一起,事情变得更加复杂,但聚合不会计算多次(如果可能)。