2017-08-25 15 views
4

说我有这个疑问:HAVING和SELECT中的计算是否表示它将执行两次?

SELECT CompanyId, COUNT(*) as Total 
FROM Customer 
GROUP BY CompanyId 
HAVING COUNT(*) > 100 

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

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

我正在使用MS SQL 2012,并且不能执行HAVING Total > 100

+1

同类问题https://dba.stackexchange.com/questions/119575/how-to-avoid-invoking-functions-twice-when-using-group-by-and-having/119578 – OutOfMind

回答

3

如果您对如何处理您的查询有疑问,请熟悉execution plans以及如何阅读它们。接下来的所有内容都是使用这些实验建立的。

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

SELECT CompanyId, SUM(Weight)/COUNT(*) 
FROM Customer 
GROUP BY CompanyId 
HAVING SUM(Weight)/COUNT(*) > 100 

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 

有四个聚集在这里:MAX(Weight)MIN(Weight)AVG(Weight)COUNT(*)。 优化程序将在一次通过中计算所有这些值,将整个值分组CompanyId,应用HAVING过滤器,然后选择所需的结果。免责声明:与所有关于优化程序的声明一样,所有这些都可能在任何SQL Server版本中发生更改,并且可能随跟踪标志,统计信息,索引和特定查询的具体情况而变化。至少,对于两个特定的数据库,至少在SQL Server 2012和2016中,上述情况是正确的,至少在索引不起作用的情况下。


  1. AVG实际上不是在自己的总和;内部优化器将其扩展为SUM/COUNT(*),并通过检查来防止被零除。所以聚合实际上是MAX,MIN,SUMCOUNT
  2. 顺序计划就是这种情况。对于一个并行计划,由于需要将多个并行扫描结合在一起,事情会变得更加复杂,但是聚合不会多次计算(如果可能)仍然如此。
1

很可能,COUNT(*)做两次,虽然这个决定是真的由查询优化器决定。

而且,这几乎没有任何区别。

在聚合数据中花费的努力是在移动数据而不是在聚合函数中,特别是像COUNT(*)这样的简单数据。一些聚合函数比较昂贵(想起COUNT(DISTINCT)),但总的来说,数据移动比简单的聚合函数更昂贵。

你没有提到的数据库,但许多允许:

HAVING Total > 100 

或使用子查询/ CTE通常对性能没有影响。

+0

啊,是的我没有提到数据库。现在更新它。 – Peter