Это чисто академический вопрос, поскольку он не вызывает проблем, и мне просто интересно услышать какие-либо объяснения поведения.
Возьмите стандартный выпуск Итцика Бен-Гана для таблицы CTE:
USE [master]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[TallyTable]
(
@N INT
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
(
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
SELECT TOP (@N) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS N FROM E8
)
GO
Выполните запрос, который создаст таблицу номеров строк в 1 миллион:
SELECT
COUNT(N)
FROM
dbo.TallyTable(1000000) tt
Посмотрите на план параллельного выполнения для этого запроса:
Обратите внимание, что «фактическое» количество строк перед оператором сбора потоков составляет 1 004 588. После оператора сбора потоков число строк составляет ожидаемый 1 000 000. Еще более странно, что значение не соответствует и будет варьироваться от запуска к запуску. Результат COUNT всегда верен.
Выполните запрос еще раз, форсируя непараллельный план:
SELECT
COUNT(N)
FROM
dbo.TallyTable(1000000) tt
OPTION (MAXDOP 1)
На этот раз все операторы показывают правильное «фактическое» количество строк.
Я пробовал это на 2005SP3 и 2008R2, одинаковые результаты на обоих. Есть мысли о том, что может вызвать это?
источник