我有這樣的結構:CTE執行多次
WITH my_cte
AS
(
SELECT y.name
FROM
WHData.dbo.vw_data x
INNER JOIN WHData.dbo.vw_DimNames y
ON x.nameKey = y.CasinoKey
WHERE DateKey >= CONVERT(CHAR(8),DATEADD(mm,-2,GETDATE() - DAY(GETDATE())) + 1,112)--two complete months ago
GROUP BY y.name
)
SELECT *
FROM WHAnalysis.dbo.tb_otherData a
WHERE NOT EXISTS
(
SELECT 1
FROM my_cte b
WHERE b.name = a.name
);
如果我在隔離運行在CTE
代碼需要3秒;但完整的腳本只是運行並運行。
如果我離開CTE
並使用索引臨時表,那麼它全部以4secs運行。
我假設發生的是CTE
正在對tb_otherData
中的每個數據記錄執行,因此可能需要,因爲有2000條記錄,2000 x 3秒....太長了!
臨時表解決方案很好,但出於興趣,有沒有辦法更改CTE
代碼,以便它能夠快速運行?我缺少一些CTE
技巧嗎?
編輯
如果我切換到一個良好的老式子查詢,則執行計劃是完全一致的:
SELECT *
FROM WHAnalysis.dbo.tb_otherData a
WHERE name not in
(
SELECT y.name
FROM
WHData.dbo.vw_data x
INNER JOIN WHData.dbo.vw_DimNames y
ON x.nameKey = y.CasinoKey
WHERE DateKey >= CONVERT(CHAR(8),DATEADD(mm,-2,GETDATE() - DAY(GETDATE())) + 1,112)--two complete months ago
GROUP BY y.name
);
熱膨脹係數是在這種情況下,只是語法糖 - 他們讓你覺得他們只評估一次,但往往並非如此。您是在尋找解釋還是解決方法(例如,在沒有臨時表的情況下編寫沒有CTE *和*的查詢)? –
@AaronBertrand實際上,我剛剛測試過,執行計劃**完全相同,如果我切換到子查詢。我實際上想知道我是否可以保留CTE,但也許我錯過了一個讓它更快的技巧?附:和前一天稍微激烈的討論a_horse_with_no_name,他告訴我,我應該像'x ascolumn'這樣的列別名,但也提到了你的名字 - 我以爲你是學校的'mycolumn = x'? – whytheq
是的,CTE只是寫一個子查詢的一種不同方式。如果我們不談論遞歸,他們可能會相同地進行優化。是的,我是'別名=專欄',但它只是一個偏好,不值得爭論。我會反對使用'column'作爲'alias''或'alias'= column'的人,但僅僅是爲了擺脫困惑和棄用的愚蠢的字符串分隔符。 –