2009-10-07 61 views
12

我有一個複雜的查詢,需要在後續查詢(實際更新語句)中使用。我已經嘗試使用CTE和臨時表。使用CTE的性能與臨時表方法相比是非常糟糕的。它的東西像15秒比毫秒。爲了簡化測試,而不是在隨後的查詢中加入CTE/Temp表,我只需從中選擇*。在這種情況下,他們表現相同。SQL 2005 CTE vs TEMP表在其他表的連接中使用時的性能

我已經看過這兩種方法的執行計劃,並在隨後的查詢中加入連接,然後簡單地選擇*。通過簡單的選擇查詢計劃大致相同,但隨後的選擇查詢計劃不是。具體來說,用於創建和填充臨時表的查詢計劃部分保持不變,而用於創建和填充CTE的查詢計劃部分隨後在具有連接的查詢中使用時發生顯着變化。

我的問題是,爲什麼CTE的創建和填充的查詢計劃隨後如何使用,而臨時表不是這樣。同樣在什麼情況下,CTE會比臨時表產生更好的性能?

*注意我也使用了表變量,它與臨時表方法相當。

感謝

回答

9

你在問一個複雜的問題,所以你會得到一個複雜的答案:這取決於。 (我討厭那個迴應)。

然而,嚴重的是,它與優化器如何選擇數據計劃(您已經知道)有關;臨時表或變量就像一個永久性結構,因爲執行計劃將執行與首先填充該結構相關的操作,然後在隨後的操作中使用該結構。 CTE不是臨時表; CTE的使用只有在後續操作使用時纔會被計算出來,因此使用會影響計劃的優化方式。

CTE的實施可重用性和維護問題,不一定表現;然而,在許多情況下(如遞歸),它們將比傳統的編碼方法更好。

13

CTE只是用於查詢的別名。

它可能(或可能不)在每次使用時重新運行。

有沒有乾淨的方式來強制SQL ServerCTE物化(如Oracle的/*+ MATERIALIZE */),而你所要做的骯髒把戲是這樣的:如果使用

CTE可以提高性能在只需要一次評估的計劃中(如HASH JOIN,MERGE JOIN等)。

在這些情況下,散列表將從CTE構建,而使用臨時表則需要評估CTE,將結果拖入臨時表並再次讀取臨時表。

+1

是的物化!定義中的PK/IX可能很好。 – crokusek 2013-03-08 17:56:39

2

我發現通常重複的CTE沒有得到性能改進。

因此,例如,如果您使用CTE填充表格,然後在稍後的查詢中加入相同的CTE,則沒有任何好處。不幸的是,CTE不是快照,而且它們必須重複使用以用於兩個單獨的語句,因此它們傾向於被評估兩次。

而不是CTE,我經常使用內聯TVF(可能包含CTE),它允許正確的重用,並且沒有比我的SP中的CTE更好或更差。

此外,我還發現,如果第一步更改統計信息,使得第二步的執行計劃總是不準確,因爲它在任何步驟運行之前進行評估,那麼執行計劃可能會很糟糕。

在這種情況下,我看手動存儲中間結果,確保它們正確編制索引,並將進程拆分爲多個SP並添加WITH RECOMPILE以確保後面的SP具有對他們所用數據有利的計劃實際上將運作。

0

我試圖創建CTE與簡單的選擇與過濾器從大表 然後3次subqueried它。

之後,對臨時表做同樣的事情。

結果是70%的時間消耗CTE -30%的時間消耗臨時表。 所以臨時表對於那些解決方案更好。

我不認爲CTE只使用選定的查詢生成臨時表,但是3次選擇一個大表。