in和exists、not in 和 not exists

1、in和exists
in是把外表和內(nèi)表作hash連接,而exists是對外表作loop循環(huán),每次loop循環(huán)再對內(nèi)表進(jìn)行查詢。
eg:A(小表),B(大表)
子查詢表小的用in,子查詢表大的用exists。
select * from A where cc in(select cc from B)  
-->效率低,用到了A表上cc列的索引;
select * from A where exists(select cc from B where cc=A.cc)  
-->效率高,用到了B表上cc列的索引。
同時(shí):
select * from B where cc in(select cc from A)  
-->效率高,用到了B表上cc列的索引
select * from B where exists(select cc from A where cc=B.cc)  
-->效率低,用到了A表上cc列的索引。
2、not in 和 not exists
not in 邏輯上不完全等同于not exists,
not in 只有當(dāng)子查詢中,select 關(guān)鍵字后的字段有not null約束或者有這種暗示時(shí)用not in,另外如果主查詢中表大,子查詢中的表小但是記錄多,則應(yīng)當(dāng)使用not in,并使用anti hash join.
如果主查詢表中記錄少,子查詢表中記錄多,并有索引,可以使用not exists,另外not in最好也可以用/*+ HASH_AJ */或者外連接+is null

eg:查詢在a表但不在b表的id

a:
image.png

b:
image.png

方法一:左查詢

select a.id,a.name from a left join b on a.id=b.id where b.id is null;
image.png

方法二:not in

select a.id,a.name from a where a.id not in (select id from b);
image.png

方法三:not exists

select * from a where not exists (select * from b where a.id=b.id);
select * from a where (select count(1) from b where a.id=b.id)=0;
image.png

方法二和方法三的區(qū)別:
方法二中的not in,會(huì)調(diào)用子查詢,不會(huì)返回null值,即a表有null但b表沒有,但是并不會(huì)返回出來,而方法三會(huì)有這個(gè)null值。
再者,如果b表中有null值,通過not in 來查詢不在b表但在a表中的數(shù)據(jù),不會(huì)返回任何值。
eg:

c:
image.png

d:
image.png

not in:

select * from c where c2 not in (select c2 from d);
image.png

not exists:

select * from c where not exists (select c2 from d where c.c2=d.c2);
image.png

通上,如果子查詢字段有非空限制,這時(shí)可以使用not in,并且可以通過提示讓它用hasg_aj或merge_aj連接。
如果查詢語句使用了not in,那么對內(nèi)外表都進(jìn)行全表掃描,沒有用到索引;而not exists的子查詢依然能用到表上的索引。所以無論哪個(gè)表大,用not exists都比not in 要快。

參考自:https://blog.csdn.net/baidu_37107022/article/details/77278381

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容