2013-07-25 46 views
0

我想實現的條件加入這樣有條件加入

declare @JoinWithT2 bit = 1; 

select T1.* from T1 
inner join T2 on (@JoinWithT2 = 0 or T1.Id=T2.Id) 

這工作得很好,當我通過@JoinWithT2值1它給我造成使用連接兩個表的,而當我通過@JoinWithT2值0它返回來自T1的所有結果,忽略連接。

這是所有工作不錯,但我關心的性能,因爲上面也可以這樣

if @JoinWithT2=0 
begin 
    select T1.* from T1 
end 
else 
begin 
    select T1.* from T1 
    inner join T2 on (T1.Id=T2.Id) 
end 

什麼是實現有條件加入的最好方式實現,第一個或第二?

我個人覺得第二個應該是性能更好,因爲當第一個查詢可使用T2

+1

它不會忽略th e加入。它總是加入桌子。如果JoinWithT2 = 1,那麼它會進行正確的連接(在ID上),如果它是0,則加入所有記錄,從而有效地將您的連接變爲交叉連接。那是你要的嗎? – GolezTrol

+4

請注意,當@ JoinWithT2爲0時,第一個查詢不是**等同於從T1選擇T1。*,而是成爲隱式笛卡爾連接 - 請參閱http://sqlfiddle.com/# !3/3f574/3 –

+0

是的。實際上,如果'@ JoinWithT2'的值爲0,我會忽略連接。 –

回答

2

我很困惑不涉及T2的。下面應該做的無論是笛卡爾乘積或內部聯接,取決於JoinWithT2值:

declare @JoinWithT2 bit = 1; 

select T1.* 
from T1 inner join 
    T2 
    on (@JoinWithT2 = 0 or T1.Id=T2.Id); 

@JoinWithT20那麼on條款始終是真實的。這使得join等同於cross join

下面是做加盟或採取的第一個表條件邏輯:

declare @JoinWithT2 bit = 1; 

select T1.* 
from T1 left outer join 
    T2 
    on (@JoinWithT2 = 1 and T1.Id=T2.Id) 
where @JoinWithT2 = 0 or T2.Id is not null; 

從性能的角度來看,在if的另一份聲明中,一般會表現得更好。有更多的信息可供SQL引擎優化。但是,如果您的索引號爲T2(id),則相對於查詢的其他部分(如將結果返回給用戶),性能差異可能並不重要。

1

這種情況下,最好的選擇可能是動態SQL,或者在新版本的SQL服務器中的條件不如舊的那樣糟糕。 if語句很好,但在添加兩個或三個其他可能或不可以加入的表(取決於特定條件)後很難維護。隨着時間的推移,條件可能會變慢,並且更多的事情會被添加到查詢中。使用這組特定的參數來構建搜索類型查詢通常是最佳選擇。

您可能需要閱讀:

http://www.sommarskog.se/dyn-search-2008.html

http://www.sommarskog.se/dyn-search-2005.html

1

爲什麼你需要一個連接,如果你不選擇任何東西(如果有啊使用SQL Server 2005或更早重新)從T2?

select T1.* 
from T1 
where @JoinWithT2 = 0 or T1.Id in (select T2.Id from T2); 
1

靜態的解決方案:同樣可以通過類似的東西來實現

CREATE VIEW Person.vBusinessEntityAddressWithInfo 
AS 
SELECT bea.AddressID,bea.AddressTypeID,bea.BusinessEntityID,bea.ModifiedDate, 
     a.PostalCode AS AddressPostalCode,a.City AS AddressPostalCity 
FROM Person.BusinessEntityAddress bea 
JOIN Person.[Address] a ON bea.AddressID=a.AddressID; 
GO 
-- Test #1: columns from only one table Person.BusinessEntityAddress 
SELECT v.AddressID,v.BusinessEntityID 
FROM Person.vBusinessEntityAddressWithInfo v 
GO 
-- Test #2: columns from both tables 
SELECT v.AddressID,v.BusinessEntityID,v.AddressPostalCode 
FROM Person.vBusinessEntityAddressWithInfo v 
GO 

如果我看的執行計劃,那麼我可以看到,對於Test #1 SQL Server只使用Person.BusinessEntityAddress表(見FK elimination;另見本answer)和Test #2 SQL Server使用兩個表: enter image description here

另一個「靜態」(或多或少)解決方案:

DECLARE @Type BIT; 
SET  @Type=0; 

SELECT bea.*,NULL AS AddressPostalCode,NULL AS AddressPostalCity 
FROM Person.BusinessEntityAddress bea 
WHERE @Type=0 
UNION ALL 
SELECT bea.*,a.PostalCode AS AddressPostalCode,a.City AS AddressPostalCity 
FROM Person.BusinessEntityAddress bea 
JOIN Person.[Address] a ON bea.AddressID=a.AddressID 
WHERE @Type=1; 

如果我執行這個查詢與@Type=0SET STATISTICS IO ON那麼SQL Server將來自BusinessEntityAddress讀取數據:

Table 'Worktable'. Scan count 0, logical reads 0 
Table 'Worktable'. Scan count 0, logical reads 0 
Table 'BusinessEntityAddress'. Scan count 1, logical reads 112 

,當我執行相同的查詢與@Type=1然後SQL Server將從兩個表讀取數據:

Table 'Worktable'. Scan count 0, logical reads 0 
Table 'Address'. Scan count 1, logical reads 216 
Table 'BusinessEntityAddress'. Scan count 1, logical reads 112 
Table 'Worktable'. Scan count 0, logical reads 0