最近沒啥活幹,複習下基礎,在 俄國一個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
搬運一下結果總結,有興趣的看原文
結果是否相同?
首先對於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 )