4

У меня вопрос о том, как MS SQL оценивает функции внутри CTE. Несколько поисков не привели к каким-либо результатам, связанным с этой проблемой, но я извиняюсь, если это общеизвестно, и я просто отстаю от кривой. Это было бы не в первый раз :-)Оценка CTE в SQL Server 2005

Этот запрос является упрощенной (и, очевидно, менее динамичной) версией того, что я на самом деле делаю, но у нее есть проблема, с которой я столкнулся. Это выглядит следующим образом:

CREATE TABLE #EmployeePool(EmployeeID int, EmployeeRank int); 

INSERT INTO #EmployeePool(EmployeeID, EmployeeRank) 
    SELECT 42, 1 
    UNION ALL 
    SELECT 43, 2; 

DECLARE @NumEmployees int; 
SELECT @NumEmployees = COUNT(*) FROM #EmployeePool; 

WITH RandomizedCustomers AS (
    SELECT CAST(c.Criteria AS int) AS CustomerID, 
     dbo.fnUtil_Random(@NumEmployees) AS RandomRank 
    FROM dbo.fnUtil_ParseCriteria(@CustomerIDs, 'int') c) 
SELECT rc.CustomerID, 
     ep.EmployeeID 
    FROM RandomizedCustomers rc 
    JOIN #EmployeePool ep ON ep.EmployeeRank = rc.RandomRank; 

DROP TABLE #EmployeePool; 

можно предположить о всех казнях выше следующее:

  • Результат dbo.fnUtil_Random() всегда является INT значение больше нуля и меньше или равно аргумент передан. Поскольку он вызывается выше с @NumEmployees, который имеет значение 2, эта функция всегда равна 1 или 2.

  • Результат dbo.fnUtil_ParseCriteria(@CustomerIDs, 'int') создает таблицу с одним столбцом, одну строку, Н. С. sql_variant с базовым типом «межд», который имеет значение 219935.

Учитывая приведенное выше допущение, что имеет смысл (для меня, во всяком случае), что результат выражения выше всегда должен производить два -колоночная таблица, содержащая одну запись - CustomerID и EmployeeID. Идентификатор клиента всегда должен быть значением int 219935, а EmployeeID должен быть либо 42, либо 43.

Однако это не всегда так. Иногда я получаю ожидаемую единую запись. В других случаях я получаю две записи (по одному для каждого EmployeeID), а третьи - у меня нет записей. Однако, если я заменил RandomizedCustomers CTE на истинную временную таблицу, проблема полностью исчезнет.

Каждый раз, когда я думаю, что у меня есть объяснение этого поведения, он не имеет смысла или невозможен, поэтому я не могу объяснить, почему это произойдет. Поскольку проблема не возникает, когда я заменяю CTE на временную таблицу, я могу только предположить, что она имеет какое-то отношение к функциям внутри CTE, которые оцениваются во время присоединений к этому CTE. Есть ли у вас какие-либо теории?

ответ

3

SQL Server оптимизатор может решить, стоит ли переоценивать CTE или нет.

Например, этот запрос:

WITH q AS 
     (
     SELECT NEWID() AS n 
     ) 
SELECT * 
FROM q 
UNION ALL 
SELECT * 
FROM q 

будет производить два разных NEWID() «с, однако, если вы используете кэшируетесь XML плана обернуть CTE в Eager Spool операции запись будет одинаковой.

+0

Я полностью понимаю сейчас. Большое спасибо за Вашу помощь! – Jammer

Смежные вопросы