내 응용 프로그램에 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_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 작업으로 Null 값이 제거됩니다.
이는 2147483647에서 오버플로가 발생하고 연산자에 의해 마지막 행 (2150000000)이 처리 된 COUNT
후 계속되어야 함을 나타냅니다 .int
COUNT
NULL
비교를 통해 COUNT
표현식을 SUM(CASE WHEN N < 2150000000 THEN 1 END)
리턴으로 대체
메시지 8115, 수준 16, 상태 2, 줄 1 식을 데이터 유형 int로 변환하는 산술 오버플로 오류
아니오 ANSI
에 대한 경고 NULL
. 필자는이 경우 2,150,000,000 행에 도달하기 전에 집계 자체에서 오버플로가 발생했다고 결론을 내 렸습니다.