为什么SQL Server在将它与一个int变量进行比较之前需要将count(*)结果转换为int?


11

我的应用程序中有很多查询,在Have子句中,我有count聚合函数与int变量的比较。在查询计划中,我可以在比较之前看到一个implicit_convert。我想知道为什么会这样,因为根据sql Server文档,count函数的返回类型是int。那么为什么要有一个隐式转换来比较两个int值呢?

以下是一个这样的查询计划的一部分,其中@IdCount被定义为一个int变量。

|-过滤器(WHERE:([[Expr1022] = [@ IdCount])))    
 |-计算标量(DEFINE:([[Expr1022] = CONVERT_IMPLICIT(int,[Expr1028],0))) 
  |-流聚合(组BY:([[MOCK_DB]。[dbo]。[Scope]。[ScopeID])DEFINE:([Expr1028] = Count(*)))

Answers:


17

您将其与integer变量进行比较的事实是无关紧要的。

的计划COUNT始终有一个CONVERT_IMPLICIT(int,[ExprNNNN],0))位置ExprNNNN,该位置表示表示的结果的表达式的标签COUNT

我一直以为,最终用于的代码COUNT将调用与相同的代码,COUNT_BIG并且必须进行强制转换才能将其bigint结果转换回int

实际上COUNT_BIG(*),在查询计划中甚至没有区别COUNT(*)。两者都显示为Scalar Operator(Count(*))

COUNT_BIG(nullable_column)确实在执行计划中与有所区别,但是执行计划COUNT(nullable_column) 仍然隐式转换到int

下面是这种情况的一些证据。

WITH 
E1(N) AS 
(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)                                       -- 1*10^1 or 10 rows
, E2(N) AS (SELECT 1 FROM E1 a, E1 b)   -- 1*10^2 or 100 rows
, E4(N) AS (SELECT 1 FROM E2 a, E2 b)   -- 1*10^4 or 10,000 rows
, E8(N) AS (SELECT 1 FROM E4 a, E4 b)   -- 1*10^8 or 100,000,000 rows
, E16(N) AS (SELECT 1 FROM E8 a, E8 b)  -- 1*10^16 or 10,000,000,000,000,000 rows
, T(N) AS (SELECT TOP (2150000000) 
                  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS N FROM E16)
SELECT COUNT(CASE WHEN N < 2150000000 THEN 1 END)
FROM T 
OPTION (MAXDOP 1)

在我的桌面上运行大约需要7分钟,并返回以下内容

消息8115,第16级,州2,第1行
将表达式转换为数据类型int的算术溢出错误。
警告:通过合计或其他SET操作消除了空值。

这表示COUNT必须在a int溢出(在2147483647)并且COUNT操作员处理了最后一行(2150000000)之后导致必须NULL返回的消息之后,必须继续执行操作。

通过比较将COUNT表达式替换为SUM(CASE WHEN N < 2150000000 THEN 1 END)return

消息8115,第16级,州2,第1行
将表达式转换为数据类型int的算术溢出错误。

没有ANSI关于的警告NULL。从中可以得出结论,在这种情况下,溢出发生在聚合本身之前,直到达到第2150,000,000行。


@PaulWhite-谢谢。我应该看一下XML。我正在查看ScalarOperatorSSMS属性窗口中显示的值。
马丁·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.