NOT IN ,NOT EXISTS 區別 11G改變
先看兩個查詢。
select count(*) from wxh_tbd where object_id not in (1,2,3);
select count(*) from wxh_tbd where object_id not in (1,2,3);
COUNT(*)
----------
20204
select count(*) from wxh_tbd where object_id not in (1,2,3,null);
----------
20204
select count(*) from wxh_tbd where object_id not in (1,2,3,null);
COUNT(*)
----------
0
很多人會覺得奇怪,怎麼多了一個NULL值,第二個查詢就沒返回了?
第二個查詢可以拆分為:
select count(*) from wxh_tbd where object_id!=1 and object_id!=2 and object_id!=3 and object_id!=null;
not in拆分後,是and的關係,只要一個不為true,那麼整條表示式都是false,返回為空。
----------
0
很多人會覺得奇怪,怎麼多了一個NULL值,第二個查詢就沒返回了?
第二個查詢可以拆分為:
select count(*) from wxh_tbd where object_id!=1 and object_id!=2 and object_id!=3 and object_id!=null;
not in拆分後,是and的關係,只要一個不為true,那麼整條表示式都是false,返回為空。
因此對於類似這樣的查詢
select object_id from wxh_tbd where object_id not in ( select object_id from wxh_tbd1);
只要子查詢返回的結果集裡有空值,那麼整個結果集都是空。因為每個wxh_tbd.OBJECT_ID都是要跟NULL值做比較的,做比較的結果是FALSE.
select object_id from wxh_tbd where object_id not in ( select object_id from wxh_tbd1);
只要子查詢返回的結果集裡有空值,那麼整個結果集都是空。因為每個wxh_tbd.OBJECT_ID都是要跟NULL值做比較的,做比較的結果是FALSE.
無論如何in不存在這樣的問題。
select count(*) from wxh_tbd where object_id in (1,2,3,null);
可以拆分成:
select count(*) from wxh_tbd where object_id=1 or object_id=2 or object_id=3 or object_id=null;
跟NOT IN不同,IN拆分後是OR的關係,只要有一個為true,那麼表示式就是true,就可以返回結果。
select count(*) from wxh_tbd where object_id in (1,2,3,null);
可以拆分成:
select count(*) from wxh_tbd where object_id=1 or object_id=2 or object_id=3 or object_id=null;
跟NOT IN不同,IN拆分後是OR的關係,只要有一個為true,那麼表示式就是true,就可以返回結果。
11G以前not in經常會導致問題。拿上面的查詢來說:
select object_id from wxh_tbd where object_id not in ( select object_id from wxh_tbd1);
如果wxh_tbd1.object_id,wxh_tbd.object_id上沒有非空約束,那麼查詢計劃會走FILTER,而且往往wxh_tbd1上是全表掃描。走不上NL,HASH.之所以走全表掃描可能基於一個簡單的原因,NULL值不包含在索引裡。
11G以後呢?
explain plan for
select object_id from wxh_tbd where object_id not in ( select object_id from wxh_tbd1);
Explained.
@display
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4021671869
---------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 4021671869
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20414 | 199K| 131 (1)| 00:00:02 |
|* 1 | HASH JOIN ANTI NA | | 20414 | 199K| 131 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL| WXH_TBD | 20446 | 99K| 65 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| WXH_TBD1 | 20411 | 99K| 65 (0)| 00:00:01 |
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 20414 | 199K| 131 (1)| 00:00:02 |
|* 1 | HASH JOIN ANTI NA | | 20414 | 199K| 131 (1)| 00:00:02 |
| 2 | TABLE ACCESS FULL| WXH_TBD | 20446 | 99K| 65 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| WXH_TBD1 | 20411 | 99K| 65 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
---------------------------------------------------
1 - access("OBJECT_ID"="OBJECT_ID")
其實11G的這種最佳化在我看來有點遲了,早就應該可以實現,無非是加一些IF ELSE判斷。掃描WXH_TBD表,扔掉為空的記錄,BUILD出HASH表。跟WXH_TBD1表做HASH,如果WXH_TBD1表裡存在NULL值,立馬終止查詢,返回結果空。
其實11G的這種最佳化在我看來有點遲了,早就應該可以實現,無非是加一些IF ELSE判斷。掃描WXH_TBD表,扔掉為空的記錄,BUILD出HASH表。跟WXH_TBD1表做HASH,如果WXH_TBD1表裡存在NULL值,立馬終止查詢,返回結果空。
11G即使表上都沒NOT NULL約束,也可以走jion了,執行計劃出現了 NA關鍵字,目前只發現可以走hash join.
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
|* 1 | FILTER | | | | |
| 2 | TABLE ACCESS FULL | WXH_TBD | | | |
|* 3 | TABLE ACCESS FULL | WXH_TBD1 | | | |
--------------------------------------------------------------------
11G以前無論如何不能走JION,只能走FILTER.
再看看NOT EXISTS對於空值的返回順序:
| Id | Operation | Name | Rows | Bytes | Cost |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | |
|* 1 | FILTER | | | | |
| 2 | TABLE ACCESS FULL | WXH_TBD | | | |
|* 3 | TABLE ACCESS FULL | WXH_TBD1 | | | |
--------------------------------------------------------------------
11G以前無論如何不能走JION,只能走FILTER.
再看看NOT EXISTS對於空值的返回順序:
select object_id from wxh_tbd where not exists ( select 1 from wxh_tbd1 where wxh_tbd1.object_id=wxh_tbd.object_id);
如果走hash,WXH_TBD為build table最先返回的是空值。道理其實很簡單,HASH 表裡空值不能被BUILD進去,可以掃描到空值就直接返回結果。如果wxh_tbd1為build table ,空值是混合在記錄裡的。
如果走hash,WXH_TBD為build table最先返回的是空值。道理其實很簡單,HASH 表裡空值不能被BUILD進去,可以掃描到空值就直接返回結果。如果wxh_tbd1為build table ,空值是混合在記錄裡的。
select object_id from wxh_tbd where not exists ( select /*+ swap_join_inputs(wxh_tbd1) */1 from wxh_tbd1 where wxh_tbd1.object_id=wxh_tbd.object_id);
如果走nest loop ,null值是混合在記錄裡的。
對於not in,如果在wxh_tbd表裡存在空值,wxh_tbd1表裡沒空值,那麼整個查詢會返回符合條件的結果集,但是空值不會作為結果返回。
對於not exists,如果在wxh_tbd表裡存在空值,那麼整個查詢會返回符合條件的結果集,而且空值會作為結果返回。
對於not exists,如果在wxh_tbd表裡存在空值,那麼整個查詢會返回符合條件的結果集,而且空值會作為結果返回。
理論上,IN 與EXISTS是完全等價的,但是各個ORACLE版本可能執行計劃存在差異,(10G以後應該無任何差異了)。
NOT IN 與NOT EXISTS的差異根據有NULL的不同而不同。如果作為條件判斷的欄位都存在NOT NULL約束,那麼這種差異也就不存在了。
NOT IN 與NOT EXISTS的差異根據有NULL的不同而不同。如果作為條件判斷的欄位都存在NOT NULL約束,那麼這種差異也就不存在了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22034023/viewspace-715280/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- EXISTS、IN、NOT EXISTS、NOT IN用法區別
- EXISTS、IN、NOT EXISTS、NOT IN的區別(ZT)
- in 和 exists區別
- exists和not exists及in和not in的用法與區別
- NOT IN 與NOT EXISTS的區別何在?
- oracle in與exists 的區別Oracle
- oracle中in和exists的區別Oracle
- SQL語句中exists和in的區別SQL
- 大神級回答exists與in的區別
- (轉)ORACLE 中IN和EXISTS的區別Oracle
- in和exists的一些區別
- SQL中IN和EXISTS用法的區別SQL
- 詳解not in與not exists的區別與用法
- [精選] SQL中的IN與NOT IN、EXISTS與NOT EXISTS的區別及效能分析SQL
- iOS UIButton之改變有效點選區域(改變熱區)iOSUI
- exists改為內連線
- not exists改為外連線
- 對線面試官:SQL中的IN與NOT IN、EXISTS與NOT EXISTS的區別及效能分析面試SQL
- 11g 改變SQL執行計劃SQL
- 子查詢中的IN與EXISTS的區別(轉)
- JS中改變this的指向 call、apply 和 bind 的區別JSAPP
- 區塊鏈改變網路區塊鏈
- 區塊鏈如何改變AI區塊鏈AI
- SQL中IN,NOT IN,EXISTS,NOT EXISTS的用法和差別SQL
- 在關聯子查詢中in與exists的區別
- oracle sql tuning_in與exists的區別_轉摘OracleSQL
- fs.exists 與 fs.access的區別是什麼
- impdp匯入時使用table_exists_action引數的區別
- not exists 中from 後面不同寫法帶來的效率區別
- 如何改變IP地址到別的城市
- 改變無法改變的Query 變數變數
- 成員變數和區域性變數的區別變數
- 修改全域性變數時,可變型別和不可變型別的區別變數型別
- 11g改變了DELETE語句的執行計劃delete
- 改變表中非空欄位的型別型別
- 19、Overload和Override的區別。Overloaded的方法是否可以改變返回值的型別?IDE型別
- Linux 下改變時區及時鐘同步Linux
- Python中類變數、成員變數、區域性變數的區別Python變數