Тот факт, что вы сравниваете его с 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
должен был продолжаться после int
переполнения (в 2147483647) и последняя строка (2150000000) был обработан COUNT
оператором, что привело к сообщению о NULL
возвращении.
Для сравнения заменим COUNT
выражение на SUM(CASE WHEN N < 2150000000 THEN 1 END)
return
Сообщение 8115, уровень 16, состояние 2, строка 1
Ошибка арифметического переполнения при преобразовании выражения в тип данных int.
без ANSI
предупреждения о NULL
. Из чего я делаю вывод, что переполнение произошло в этом случае во время самой агрегации до достижения строки 2 150 000 000.
ScalarOperator
значение, показанное в окне свойств SSMS.