Oracle中left join中右表的限制條件

2021-09-22 18:49:24 字數 4505 閱讀 3570

sql中最簡單形式的left join,是直接根據關聯字段,以左表為基準,對右表進行匹配。在select語句中選取的字段,如果有右表的記錄(一般都是需要右表的某些記錄的),取出配對成功的右表記錄中對應的這個欄位的值;否則,直接置null。這本身就是left join的特點:保證左表記錄完整,右表只是輔助匹配。

直接看例子,為了演示,準備了兩張測試表test1test2

對照上面例子解釋一下這個結果:以左表test2為基準,用右表test1asin欄位和test2parent_asin字段進行匹配,取出test2的全部資料和test1market_place_id字段。對於test2中的第一條記錄,因為右表中有兩條記錄符合的asin='parent1',只是market_place_id不同而已(分別為1、2)。於是這兩條記錄都會作為符合條件的記錄加入結果集。這時,雖然是以左表為基準,但是這條記錄卻在結果集中產生了兩條對應的記錄。這點要稍加注意:以左表為基準並不意味著結果集的記錄數量=左表的記錄數量!

再回過頭來看結果集的5條記錄,由id字段可以很好的區分出每條記錄是由左表的哪條記錄對應產生的。這裡,最後兩條記錄可以很好的體現出left join的特點。

這裡,我們忽略左表有過濾條件場景的討論,因為在left join中左表作為基準表,對他的過濾直接反應在sql的where字句中,效果上也相當於單錶selectwhere字句過濾,縮小左表範圍後,再和右表做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加上了對右表test1market_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已經被換成了indexrange 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。這就解釋了為什麼最後的結果集只有兩條記錄。

同樣思路,就本例而言,在右表testmarket_place_id欄位上建立index,同樣可以達到優化sql的目的,以下是建立index之後的sql執行計畫:

在使用left join時,右表的限制條件,在onwhere字句**現,邏輯上的語義完全不同。

過濾條件在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...