NOT IN vs. NOT EXISTS vs. LEFT JOIN/ IS NULL

最近沒啥活幹,複習下基礎,在 俄國一個sql在線練習網站 上作點兒sql題,常常遇到這類問題:mysql

相關聯的左(l), 右(r) 表,取出左表中存在,可是右表中不存在的行(Select values present in one table but missing in another one.)sql

 

有一些不完整的發現,暫寫成此文待補充數據庫

 

這個問題有三種寫法:oracle

1. 左鏈接後,選擇右表中鏈接鍵爲null的記錄(LEFT JOIN/ IS NULL)測試

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

 

2. NOT IN網站

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

 

3. EXISTSspa

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

 

其中第一種方法以前沒怎麼見過,算是新知識。 code

研究過程當中在翻到不少關於三者比較的文章,原文連接如server

SQL Serverblog

Oracle

MySQL

 

搬運一下結果總結,有興趣的看原文

 

結果是否相同?

首先對於NOT EXISTS 和 LEFT JOIN/IS NULL 的結果老是徹底相同的。

若是鏈接字段非空,那麼三者的語義在不一樣數據庫環境下也是徹底相同的。

 

當被判斷字段可空的時候

Sql Server 和 ORACLE (引文中認爲oracle中語義相同,但通過測試和參考AskTom 中的回答,我認爲Oracle 的狀況與Sql Server 一致)中, NOT IN 與另外兩個的結果不不一樣。

也就是說,當右表查詢結果中字段值爲空的時候NOT IN (NULL) 不會返回任何結果, 由於NULL與NULL並不相等。

如,當l_left 和l_right 是徹底相同的表,且全部的value全都是空的話, NOT IN返回結果數量是0,而NOT EXISTS是所有

 

  MySQL暫未測試,待補充。預計結論同上。

 

效率比較?

(本部分純搬運)

SQL Sever 中NOT IN 的效率低於NOT EXISTS和LEFT JOIN/ IS NULL,後二者的執行計劃相同

MySQL對三者生成三個不一樣的執行計劃,其中NOT EXISTS 的效率明顯低於NOT IN 和 LEFT JOIN/ IS NULL。

對於Oracle,三者生成徹底相同的執行計劃,cost徹底相同。(此爲原文,結論存疑)

(筆者簡單測試了三種狀況,結果不完整,待補充

1. 1萬行作右表,主外鍵鏈接的,NOT IN 和NOT EXIST 計劃一致,使用NESTED LOOPS ANTI, LEFT JOIN 使用HASH JOIN OUTER,最後一個比前邊的效率略好5%

2.1 兩個小於100行的表, 主外鍵鏈接, LEFT JOIN和NOT EXISTS 計劃相同,使用HASH JOIN RIGHT ANTI ,NOT IN 使用FITER, 後者效率差22%

2.2 同上兩個小表,可空字段鏈接,狀況徹底同2.1 )

相關文章
相關標籤/搜索