对线面试官：SQL中的IN与NOT IN、EXISTS与NOT EXISTS的区别及性能分析

1、in和exists

in是把外表和内表作hash连接，而exists是对外表作loop循环，每次loop循环再对内表进行查询，一直以来认为exists比in效率高的说法是不准确的。

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列的索引。

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，小心你的程序存在致命的BUG，请看下面的例子：

create table #t1(c1 int,c2 int);

create table #t2(c1 int,c2 int);

insert into #t1 values(1,2);

insert into #t1 values(1,3);

insert into #t2 values(1,2);

insert into #t2 values(1,null);

select * from #t1 where c2 not in(select c2 from #t2);  -->执行结果：无

select * from #t1 where not exists(select 1 from #t2 where #t2.c2=#t1.c2)  -->执行结果：1  3

3、in 与 = 的区别

select name from student where name in('zhang','wang','zhao');select name from student where name='zhang' or name='wang' or name='zhao'

其他分析：

1.EXISTS的执行流程

select * from t1 where exists ( select null from t2 where y = x )

for x in ( select * from t1 ) loop
if ( exists ( select null from t2 where y = x.x ) then
OUTPUT THE RECORD
end if
end loop

2.NOT IN 与NOT EXISTS:

NOT EXISTS的执行流程

select ..... from rollup R  where not exists ( select 'Found' from title T where R.source_id = T.Title_ID);

for x in ( select * from rollup ) loop
if ( not exists ( that query ) ) then
OUTPUT
end if;
end loop;

select x,y from t;

x y
------ ------
1 3
3 1
1 2
1 1
3 1
5

select * from t where x not in (select y from t t2 ) ;

select * from t where not exists (select null from t t2 where t2.y=t.x ) ;

x y
------ ------
5 NULL

not in 只有当子查询中，select 关键字后的字段有not null约束或者有这种暗示时用not in,另外如果主查询中表大，子查询中的表小但是记录多，则应当使用not in,并使用anti hash join.

NOT IN 在基于成本的应用中较好

select .....
from rollup R
where not exists ( select 'Found' from title T
where R.source_id = T.Title_ID);

select ......
from title T, rollup R
where R.source_id = T.Title_id(+)
and T.Title_id is null;

sql> select /*+ HASH_AJ */ ...
from rollup R
where ource_id NOT IN ( select ource_id
from title T
where ource_id IS NOT NULL )

select * from t1 where x in ( select y from t2 )

select *
from t1, ( select distinct y from t2 ) t2
where t1.x = t2.y;

——如果你有一定的SQL优化经验，从这句很自然的可以想到t2绝对不能是个大表，因为需要对t2进行全表的“唯一排序”，如果t2很大这个排序的性能是 不可忍受的。但是t1可以很大，为什么呢？最通俗的理解就是因为t1.x=t2.y可以走索引。

select * from t1 where exists ( select null from t2 where y = x )

for x in ( select * from t1 )
loop
if ( exists ( select null from t2 where y = x.x )
then
OUTPUT THE RECORD!
end if
end loop

——这个更容易理解，t1永远是个表扫描！因此t1绝对不能是个大表，而t2可以很大，因为y=x.x可以走t2.y的索引。

《L02 从零构建论坛系统》

《G01 Go 实战入门》

2个月前 评论

PHP&&Java @ sinosoft

46

90

465

1148