2014-01-17 24 views
2

我需要優化的查詢,其中,加入取決於條件如何使用條件連接優化查詢?

我有兩個表

表1有兩列,讓我們稱它們爲A和B的列,可涉及表2列C,

如果B欄是空的,我必須與t2.C 匹配t1.A如果B列不爲空,我必須與t2.C

匹配t1.B

最後我需要知道哪些t1上的條目在t2上沒有匹配...

要詳細瞭解,t1是客戶端的表格,A和B都是客戶端代碼。 代碼與B代碼永遠不一樣,在有B的情況下,B有優先權(B代表新的客戶代碼,但老客戶沒有它,在B爲空的情況下,A代表代碼使用)(這一切都是因爲B列是新舊客戶端B的空值)。

t2是購買表。 t2.C是客戶端代碼,但在這種情況下是單列,它存儲舊客戶端的A代碼和新客戶端的B代碼。

我唯一想做的就是知道哪些客戶還沒有購物,儘可能提高查詢效率。

我已經提出了幾個疑問,但他們是極其緩慢的,我猜是因爲條件如何處理:

第一次嘗試:

select * 
from t1 
left join t2 on (t1.A = t2.C or t1.B = t2.C) 
where t2.D is null; 

請注意,我可以使用OR條件,因爲我知道t1.A將永遠不會與t1.B相同,所以在t2.C中,它只能與A或B匹配,但不會同時存在(假設條件得到保證)。該查詢是如此之慢,它在我的SQL客戶端超時。

第二次嘗試

select * 
from t1 
left join t2 on (if(t1.B is null, t1.A = t2.C, t1.B = t2.C)) 
where t2.D is null; 

在這種情況下,對比條件取決於t1.B,如果爲空,將其與比較,如果不是的話,與B 再次查詢極其緩慢。

我想我可以只使用兩個連接,併爲每個連接使用每個條件(A或B),但我不知道如何實現它,特別是因爲我只需要獲得既不是A或B在t2上有匹配。 (即沒有t2購買的t1客戶端)

對於這種情況,我可以選擇哪些更高效的查詢?

感謝

回答

2

如果您對t1.At1.B然後我懷疑IFNULL沒有索引,將是您最好的選擇:

select * 
from t1 
left join t2 on ifnull(t1.B, t1.A) = t2.C 
where t2.D is null; 

但是,如果任一列索引,我懷疑你將使用UNION ALL獲得最佳的性能:

select * 
from t1 
left join t2 on t1.A = t2.C 
where t2.D is null 
and t1.B is null 
union all 
select * 
from t1 
left join t2 on t1.B = t2.C 
where t2.D is null 
and t1.B is not null; 

原因是,在編譯過程中優化器將不知道是否使用t1.At1.B的加入所以不能選擇一個索引並選擇一個表掃描,但是如果將它分成兩個查詢,它就知道要在連接上使用哪個列,並且可以使用適當的索引。

Example on SQL Fiddle

+0

的感謝!第一個版本,(用'ifnull')工作得很好,我看到的和我第二次嘗試的時候非常相似,我使用'on(if(t1.B is null,t1.A = t2.C,t1.B = t2.C))'而不是你的'on ifnull(t1.B,t1.A)= t2.C'。是什麼讓他們如此不同以至於你的版本比我的效率更高?我覺得這很有趣。事實上,儘管我對所有涉及的列(A,B和C)都有索引,但你的ifnull版本比聯盟全部工作速度更快(0.2 vs .6秒)。 – DiegoDD

+0

「IFNULL」的工作原因比你的if語句更好,因爲其中沒有包含「t2.C」列,因此它是靜態的,所以MySQL知道它可以使用該列上的索引,而在你的if語句中它不能算出't2.C'被用在true和false表達式中,所以它不使用索引。 – GarethD

+0

哦,現在我明白了!所以它不是因爲簡單地使用'ifnull(x,y)'而不是'if(x是null,y,x)',而是因爲比較列在if之外。因此,使用'(if(t1.B is null,t1.A,t1.B)= t2.C)'與ifnull()完全相同。謝謝! – DiegoDD

1

唉,做有條件的加入往往會導致查詢性能非常差。在這種情況下,您正在測試兩個值,並且可能會查看是否存在這兩個值。試着將其分成兩個連接:

select * 
from t1 left join 
    t2 
    on t1.A = t2.C left join 
    t2 t2a 
    on t1.B = t2a.C 
where t2.D is null and t2a.D is null; 

這將允許查詢使用A,B和C上的索引。