sou*_*ser 12 sql-server-2008 sql-server
我的应用程序中有很多查询,其中在 have 子句中,我将 count 聚合函数与 int 变量进行了比较。在查询计划中,我可以在比较之前看到一个implicit_convert。我想知道为什么会发生这种情况,因为根据 sql server 文档,count 函数的返回类型是 int。那么为什么要进行隐式转换来比较两个 int 值呢?
以下是一个这样的查询计划的一部分,其中 @IdCount 被定义为一个 int 变量。
|--过滤器(WHERE:([Expr1022]=[@IdCount])) |--计算标量(DEFINE:([Expr1022]=CONVERT_IMPLICIT(int,[Expr1028],0))) |--Stream Aggregate(GROUP BY:([MOCK_DB].[dbo].[Scope].[ScopeID]) DEFINE:([Expr1028]=Count(*)))
Mar*_*ith 17
您将其与integer变量进行比较的事实无关紧要。
的计划COUNT总是有一个CONVERT_IMPLICIT(int,[ExprNNNN],0))whereExprNNNN是表示 的结果的表达式的标签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)
Run Code Online (Sandbox Code Playgroud)
这需要大约 7 分钟才能在我的桌面上运行并返回以下内容
Msg 8115, Level 16, State 2, Line 1 将表达式转换为数据类型 int 时出现算术溢出错误。 警告:空值被聚合或其他 SET 操作消除。
这表明COUNT在 aint溢出(在 2147483647 处)并且最后一行 (2150000000) 被COUNT操作员处理后,必须继续进行,从而导致有关NULL返回的消息。
通过比较的COUNT方式用SUM(CASE WHEN N < 2150000000 THEN 1 END)返回替换表达式
Msg 8115, Level 16, State 2, Line 1 将表达式转换为数据类型 int 时出现算术溢出错误。
没有ANSI警告NULL。从中我得出结论,在达到第 2,150,000,000 行之前,在聚合过程中发生了溢出。
| 归档时间: |
|
| 查看次数: |
5494 次 |
| 最近记录: |