왜 SQL Server가 count (*) 결과를 int 변수와 비교하기 전에 int로 변환해야합니까? 한 쿼리가 많이 있습니다. 쿼리 계획에서 비교하기

내 응용 프로그램에 having 절에서 많은 집계 함수와 int 변수를 비교 한 쿼리가 많이 있습니다. 쿼리 계획에서 비교하기 전에 implicit_convert를 볼 수 있습니다. SQL Server 설명서에 따라 반환 함수의 반환 유형이 int이기 때문에 이것이 왜 발생하는지 알고 싶습니다. 그렇다면 두 개의 int 값을 비교하기 위해 암시 적 변환이 필요한 이유는 무엇입니까?

다음은 @IdCount가 int 변수로 정의 된 쿼리 계획 중 하나입니다.

|-필터 (WHERE : ([Expr1022] = [@ IdCount]))
 |-컴퓨 트 스칼라 (DEFINE : ([Expr1022] = CONVERT_IMPLICIT (int, [Expr1028], 0)))
  |-스트림 집계 (GROUP BY : ([MOCK_DB]. [dbo]. [Scope]. [ScopeID])) DEFINE : ([Expr1028] = Count (*)))


답변

integer변수 와 변수를 비교한다는 사실 은 관련이 없습니다.

에 대한 계획은 COUNT항상 CONVERT_IMPLICIT(int,[ExprNNNN],0))where ExprNNNN의 결과를 나타내는 표현식의 레이블입니다 COUNT.

내 가정은 항상 COUNT같은 코드를 호출 하는 코드를 끝내고 COUNT_BIGbigint결과 를로 변환하기 위해 캐스트가 필요하다고 가정 했습니다 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 작업으로 Null 값이 제거됩니다.

이는 2147483647에서 오버플로가 발생하고 연산자에 의해 마지막 행 (2150000000)이 처리 된 COUNT후 계속되어야 함을 나타냅니다 .intCOUNTNULL

비교를 통해 COUNT표현식을 SUM(CASE WHEN N < 2150000000 THEN 1 END)리턴으로 대체

메시지 8115, 수준 16, 상태 2, 줄 1
식을 데이터 유형 int로 변환하는 산술 오버플로 오류

아니오 ANSI에 대한 경고 NULL. 필자는이 경우 2,150,000,000 행에 도달하기 전에 집계 자체에서 오버플로가 발생했다고 결론을 내 렸습니다.