4

我有一個關於MS SQL如何評估CTE內部函數的問題。一些搜索沒有得出任何有關這個問題的結果,但我很抱歉,如果這是常識,我只是在曲線後面。這不會是第一次:-)評估SQL Server 2005中的CTE

這個查詢是我實際做的簡化(並且明顯不那麼動態)的版本,但它確實表現出我遇到的問題。它看起來像這樣:

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')結果產生一列,一列表,包含3納秒與鹼型,其具有的值219935.

鑑於上述假設「INT」的SQL_VARIANT,是有意義(我,反正)該表達式的結果上述應該總是產生兩包含一條記錄的列表 - CustomerID和一個EmployeeID。 CustomerID應始終爲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計劃包裹CTEEager Spool操作,這些記錄將是相同的。

+0

我現在完全明白了。非常感謝您的幫助! – Jammer 2010-03-26 15:46:32