I have many queries in my application where in the having clause, I have comparison of count aggregate function with int variable.
In the query plans, I can see an implicit_convert before the comparison.
I want to know why this happens because as per sql server documentation, the return type of count function is int. So why should there be an implicit conversion for comparison of two int values?
Following is a part of one such query plan where @IdCount is defined as an int variable.
|--Filter(WHERE:([Expr1022]=[@IdCount])) |--Compute Scalar(DEFINE:([Expr1022]=CONVERT_IMPLICIT(int,[Expr1028],0))) |--Stream Aggregate(GROUP BY:([MOCK_DB].[dbo].[Scope].[ScopeID]) DEFINE:([Expr1028]=Count(*)))
Best Answer
The fact that you are comparing it against an
integer
variable is irrelevant.The plan for
COUNT
always has anCONVERT_IMPLICIT(int,[ExprNNNN],0))
whereExprNNNN
is the label for the expression representing the result of theCOUNT
.My assumption has always been that the code for
COUNT
just ends up calling the same code asCOUNT_BIG
and the cast is necessary to convert thebigint
result of that back down toint
.In fact
COUNT_BIG(*)
isn't even distinguished in the query plan fromCOUNT(*)
. Both show up asScalar Operator(Count(*))
.COUNT_BIG(nullable_column)
does get distinguished in the execution plan fromCOUNT(nullable_column)
but the latter still gets an implicit cast back down toint
.Some evidence that this is the case is below.
This takes about 7 minutes to run on my desktop and returns the following
Which indicates that the
COUNT
must have continued on after anint
would have overflowed (at 2147483647) and the last row (2150000000) was processed by theCOUNT
operator leading to the message aboutNULL
being returned.By way of comparison replacing the
COUNT
expression withSUM(CASE WHEN N < 2150000000 THEN 1 END)
returnswith no
ANSI
warning aboutNULL
. From which I conclude the overflow happened in this case during the aggregation itself before row 2,150,000,000 was reached.