2010-11-08 51 views
3

我有一個包含多個語句和UNION ALL的大型SQL查詢。我現在正在做這樣的事情:有條件的選擇查詢

DECLARE @condition BIT; 
SET @condition = 0; 

SELECT * FROM table1 
WHERE @condition = 1; 

UNION ALL 

SELECT * FROM table2 

在這種情況下,table1不會返回任何結果。但是,該查詢對於許多聯接而言很複雜(如FullTextTable)。執行計劃的估計顯示成本很高,但實際的行數和執行時間似乎表現出來。這是過濾整個查詢的最有效方式,還是有更好的方法?如果可能,我不希望第一個選擇中的任何內容運行。

+0

所以,你要做的是,如果@條件是真的,從第一個查詢中選擇並加入到第二個查詢中,否則只需選擇第二個查詢? – DForck42 2010-11-08 15:57:02

+0

@ DForck42:這是正確的,但每個選擇都很複雜,並且有很多選擇,所以請考慮一個「可擴展」的解決方案,而不是一堆if/elses。 – 2010-11-08 16:39:58

回答

1

解決這個最好的方法是通過使用動態SQL。 DForck解決方案的問題是它可能導致參數嗅探。只是爲了給出一個粗略的想法,你的查詢可能看起來像這樣

DECLARE @query VARCHAR(MAX);

IF(@condition = 0) SET @query = 'SELECT * FROM表1 UNION ALL'

SET @query = @query + 'SELECT * FROM表2'

sp_executesql的@query

這只是一個簡化的情況,但在實際實現中,您將參數化動態查詢,這將解決參數嗅探問題。這裏是關於這個問題的一個很好的解釋Parameter Sniffing (or Spoofing) in SQL Server

+1

+1參數嗅探。我不是DBA,但我不知道SQL服務器做了這樣的事情。你能解釋更多的參數嗅探嗎?存儲過程是否只緩存一個計劃總數?如果sproc有兩個完全不相關的查詢呢?在DForck的回答中,第一個查詢的執行計劃不能[完全]用於第二個查詢,那麼這將如何導致參數嗅探?謝謝! – 2010-11-08 20:15:22

+0

是的,sql服務器爲每個存儲過程創建一個計劃,它應該是每個存儲過程只有一個。所以第一次運行存儲過程時,可以說@condition = 1。然後,生成的計劃將針對DForck答案中的第一個查詢進行優化。現在,如果再次調用存儲過程,但使用@condition = 0,則SQL服務器將使用之前生成的相同計劃,這不是我們想要的。 – Sadhir 2010-11-08 20:27:34

+0

解決此問題的另一種方法是創建兩個單獨的存儲過程 - 一個執行SELECT * FROM table1,另一個執行SELECT * FROM table1 UNION SELECT * FROM table2,然後使用包裝存儲過程調用其中一個取決於@condition的值。這樣SQL服務器爲兩個存儲過程創建兩個單獨的計劃。希望能回答你的問題 – Sadhir 2010-11-08 20:28:31

1

我想你可能會對這個更好:

if (@condition=1) 
begin 

select * from table1 
union all 
select * from table2 

end 
else 
begin 

select * from table2 

end 
+0

在我的情況下,我有很多工會,選擇語句很複雜(每個30+行)。爲每個組合創建一個if/else是不可行的。我認爲你的答案對於更簡單的情況+1是合理的。 – 2010-11-08 16:44:36

2

我會想象你最終的SQL查詢與所有的工會和條件,取決於預先計算的值會變得非常複雜。如果你有興趣降低查詢的複雜性(不是爲了維護而是爲了維護),我會將個別查詢轉換爲視圖或表值函數來將該邏輯移到其他地方。然後,您可以使用其他地方提出的if @condition = 1語法。

+0

+1我曾考慮過這個問題。另外,據我所知,這將防止參數嗅探問題。 – 2010-11-08 20:11:59