sql中最簡單形式的left join
,是直接根據關聯字段,以左表為基準,對右表進行匹配。在select
語句中選取的字段,如果有右表的記錄(一般都是需要右表的某些記錄的),取出配對成功的右表記錄中對應的這個欄位的值;否則,直接置null
。這本身就是left join
的特點:保證左表記錄完整,右表只是輔助匹配。
直接看例子,為了演示,準備了兩張測試表test1
,test2
:
對照上面例子解釋一下這個結果:以左表test2
為基準,用右表test1
的asin
欄位和test2
的parent_asin
字段進行匹配,取出test2
的全部資料和test1
的market_place_id
字段。對於test2
中的第一條記錄,因為右表中有兩條記錄符合的asin='parent1'
,只是market_place_id
不同而已(分別為1、2)。於是這兩條記錄都會作為符合條件的記錄加入結果集。這時,雖然是以左表為基準,但是這條記錄卻在結果集中產生了兩條對應的記錄。這點要稍加注意:以左表為基準並不意味著結果集的記錄數量=左表的記錄數量!
再回過頭來看結果集的5條記錄,由id
字段可以很好的區分出每條記錄是由左表的哪條記錄對應產生的。這裡,最後兩條記錄可以很好的體現出left join
的特點。
這裡,我們忽略左表有過濾條件場景的討論,因為在left join
中左表作為基準表,對他的過濾直接反應在sql的where
字句中,效果上也相當於單錶select
的where
字句過濾,縮小左表範圍後,再和右表做join
,沒什麼懸念。
但是對於右表的過濾,通常有兩種主要的方式:在on
字句中加入過濾條件或者在left join
之後的where
字句中加入過濾條件。對於這兩種方式的對比,下面主要針對邏輯語義和實現效能上加以對比。
sql**
select t2.
*,t1.market_place_id from test2 t2
left
join test1 t1
on t2.parent_asin=t1.asin and t1.market_place_id=
'2'
上面這條sql
加上了對右表test1
中market_place_id
的過濾條件:只關心market_place_id
為『2』
的右表記錄。查詢結果如下。
邏輯語義上,這個結果相當於右表test1
首先進行了條件過濾,只剩下兩條記錄[(2,'parent1','2'),(3,'parent2','2')]
,然後左表test2
和這個過濾之後的結果集進行無過濾條件的left join
,於是得到了上圖的結果。
效能上,來看一下這條語句的執行計畫截圖
可以看出,t1
確實先以2為標準對market_place_id
做了一次過濾,然後,在外層,再做原來的left join
。由此可以證實上面邏輯語義結果的展示,同時也可以發現,就本例而言,如果能夠在market_place_id
上建立index
,可以直接避免內層過濾對右表進行的全表掃瞄,從而提高整個sql的執行效率。下圖為在market_place_id
上建立index
之後,同樣sql語句的執行計畫:
table full scan
已經被換成了index
的range scan
,從而也直接導致了oracle的優化器在最外層的hash join
替換為了nested loops
。(當然這個join
的方式並不能說明什麼問題,因為畢竟測試用的資料集太小,完全有可能在大資料集的真實情況下,優化器根據統計資訊還是最終使用hash join
演算法)
sql**
select t2.
*,t1.market_place_id from test2 t2
left
join test1 t1
on t2.parent_asin=t1.asin
where t1.market_place_id=
'2'
上面語句的執行結果如下:
邏輯語義上,所有的market_place_id1!='2'
的記錄(包括null
)全部被過濾掉了。
效能上,再來看一下這條語句的執行計畫:
由上面的執行計畫可以看出,oracle也是首先對右表test1
進行了market_place_id
的過濾,但是過濾之後join
操作已經不是left join
了,而是變成了普通的inner join
。這就解釋了為什麼最後的結果集只有兩條記錄。
同樣思路,就本例而言,在右表test
的market_place_id
欄位上建立index
,同樣可以達到優化sql
的目的,以下是建立index
之後的sql執行計畫:
在使用left join
時,右表的限制條件,在on
和where
字句**現,邏輯上的語義完全不同。
過濾條件在on
子句**現時,不會改變原來left join
的執行語義:以左表為基表。
過濾條件在where
字句**現時,已經改變了原來left join
的語義,相當於在最後left join
的結果集裡面再做了一次where
條件的過濾,所以已經喪失的left join
的原始語義。
效能上,其實兩者並沒有本質的區別,掃瞄路徑完全一致,只是對於後者,oracle
的內部實現,巧妙的將上面描述的語義轉換為了通過inner join
實現。這樣就保證了在真正執行時還是首先進行內層過濾,縮小右表的資料集,然後進行外層inner join
。
所以使用left join
是,有需求對右表進行過濾時,要格外小心了。
以上測試使用oracle 11g
,更老版本的優化器的執行計畫可能會不同。但最終語義上不會有差別。
Left join 中where on 的 區別
left join中where,on區別 table a id,type id type 1 1 2 1 3 2 table b id,class id class 1 1 2 2 sql語句1 select a.b.from a left join b on a.id b.id and a.typ...
sql 中 left join 的使用
left join 是以左表為基礎,查詢右表的值。如果在右表中沒用沒有資料,則為null。這裡有三張表。線路bs line id,name id主鍵 線路段bs seg id,l id,name l id關聯線路id 配變bs dsub id,seg id,name seg id關聯線路段id 它們...
Oracle資料庫 Left Join 使用之我見
在oracle 9i資料庫中使用left join這種連表查詢方式的效率是極為低下的。在專案中使用了這麼一條語句 select tmp2.company name,sum tmp2.radio send bytes tmp2.radio recv bytes 1024 1024 1024 as fl...