Oracle中left join中右表的限制條件
無過濾條件的LEFT JOIN
SQL中最簡單形式的LEFT JOIN
,是直接根據關聯欄位,以左表為基準,對右表進行匹配。在SELECT
語句中選取的欄位,如果有右表的記錄(一般都是需要右表的某些記錄的),取出配對成功的右表記錄中對應的這個欄位的值;否則,直接置NULL
。這本身就是LEFT JOIN
的特點:保證左表記錄完整,右表只是輔助匹配。
直接看例子,為了演示,準備了兩張測試表test1,test2:
select * from test1
select * from test2
select t2.*,t1.market_place_id from test2 t2
left join test1 t1
on t2.parent_asin=t1.asin
對照上面例子解釋一下這個結果:以左表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
這裡,我們忽略左表有過濾條件場景的討論,因為在LEFT JOIN
中左表作為基準表,對他的過濾直接反應在SQL的WHERE
字句中,效果上也相當於單表SELECT
的WHERE
字句過濾,縮小左表範圍後,再和右表做JOIN
,沒什麼懸念。
但是對於右表的過濾,通常有兩種主要的方式:在ON字句中加入過濾條件或者在LEFT JOIN
之後的WHERE
字句中加入過濾條件。對於這兩種方式的對比,下面主要針對邏輯語義和實現效能上加以對比。
過濾條件在ON字句中
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
演算法)
過濾條件在WHERE
子句中
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,right join,inner join的條件on和where的區別
- sql中的join、left join、right joinSQL
- oracle表空間傳輸的限制條件Oracle
- mysql中的left join、right join 、inner join的詳細用法MySql
- 深入Oracle的left join中on和where的區別詳解Oracle
- 【原】Oracle中Left Outer Join和外關聯(+)的區別Oracle
- oracle中的條件語句Oracle
- 如何在ORACLE中修改表的約束條件啊Oracle
- mysql where條件中 字串右邊的空格會忽略MySql字串
- 分享:SQL中 LEFT JOIN 左表合併去重實用技巧SQL
- oracle update left join查詢Oracle
- Oracle Left join right jionOracle
- SQL Server檢視管理中的四個限制條件SQLServer
- SQL中聯表查詢操作(LEFT JOIN, RIGHT JOIN, INNER JOIN)SQL
- MySql的join(連線)查詢 (三表 left join 寫法)MySql
- excel圖表中的條件格式化Excel
- 總結在SQL Server檢視管理中限制條件SQLServer
- Oracle -- left join 什麼情況可以直接改成joinOracle
- mysql + left joinMySql
- mysql INNER JOIN、LEFT JOIN、RIGHT JOIN;內連線(等值連線)、左連線、右連線MySql
- SQL Server檢視管理中需要遵守的四個限制條件SQLServer
- mysql left join轉inner joinMySql
- mysql 左連結 left join 條件寫在where 後面與 on後面的區別MySql
- join、inner join、left join、right join、outer join的區別
- MySQL LEFT JOIN/ INNER JOIN/RIGHT JOINMySql
- oracle的left join,right join和full join的一點介紹(R1)Oracle
- Laravel 中兩張資料表 left join 怎麼讓相同欄位不被覆蓋?Laravel
- SQL Server Left joinSQLServer
- LEFT JOIN 和JOIN 多表連線
- sql:left join和join區別SQL
- mysql中的表大小限制MySql
- Oracle 連線條件中帶有OR的測試Oracle
- model 的 with 怎麼寫 join 的條件
- 三表關聯查詢-多次LEFT JOIN...ON
- sql之left join、right join、inner join的區別SQL
- SQL中on條件與where條件的區別[轉]SQL
- Oracle中的Hash Join祥解Oracle
- Oracle中的Hash Join詳解Oracle