in,exists,not in ,not exists效率

一、in和exists效率说明

in

确定给定的值是否与子查询或列表中的值相匹配。
系统在执行in子查询时,首先执行子查询,并将获得的结果 列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。

exists

指定一个子查询,检测行的存在。
通过使用 exists,系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。

一直以来认为exists比in效率高的说法是不准确的。
如果查询的两个表大小相当,那么用in和exists差别不大。
如果两个表中一个较小,一个是大表,则子查询表大的用exists,驱动表小的用in;in 使用了驱动表的索引,exists 使用了查询表的索引。
例如:表A(小表),表B(大表)

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

2、exists 适用于外表小,内表大

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

二、not in 和 not exists说明

1、not in 并不等价于not exists

例如下面这两个句子,只有在t1.tcode不为NULL的时候,两者返回的记录才是相同的,大家在用not exists来替换not in 时可能会忽略掉这一点

 select t1.*
  from test1 t1
 where not exists (select t2.tcode from test2 t2 where t2.tcode = t1.tcode);
 select t1.* from test1 t1 where t1.tcode not in (select t2.tcode from test2 t2);

  分析一下原因:假如 select t2.tcode from test2 t2 的查询结果是 tcode1 和 null 

 将句子 select t1.* from test1 t1 where t1.tcode not in('tcode1',null);
 可以转换为 select t1.* from test1 t1 where t1.code <> 'tcode1' and t1.code <> null;
 t1.code <> null 会将所有结果不为空的过滤掉,那么结果自然为空了。
 not exists语句不会出现这种情况,因为not exists子句中写的是t2.tcode与t1.tcode的关联,null是不参与等值关联的,所以test2的tcode存在空值对最终的查询结果没有任何影响。
 
 由此可以得出结论:
 (1)、对于not exists查询,内表存在空值对查询结果没有影响;对于not in查询,内表存在空值将导致最终的查询结果为空。
 (2)、对于not exists查询,外表存在空值,存在空值的那条记录最终会输出;对于not in查询,外表存在空值,存在空值的那条记录最终将被过滤,其他数据不受影响。

 2、效率上使用not exists来代替not in

效率上应尽可能使用not exists来代替not in,尽管二者都使用了not(不能使用索引而降低速度),not exists要比not in查询效率更高。
not exists语句是一个简单的两表关联,内表与外表中存在空值本身就不参与关联,在CBO(基于成本的优化器)中常用的执行计划是hash join;
not in 中因为内表或外表中存在空值对最终结果产生的影响是hash join无法实现的,因为hash join不支持把空值放到hash中,所以它没办法处理外表和内表中存在的空值;not in 的执行计划是filter,类似nested loop;

对于hash join来说,它的时间复杂度大致相当于两个for循环(并非嵌套)O(n+m)(n,m表示内外表扫描的时间复杂度,也可以简单的理解为是内外表符合条件的行数,虽然有些不恰当),为什么这么说呢?因为hash join是先把内表的结果集全部算出来,完了之后再对外表做一个全表扫描。所以说是O(n+m)。nested loops,对于内表的符合条件的每行,都会在外表去扫描一下,看是外表否有符合条件的行。这个就相当于两个for循环嵌套了时间复杂度O(n*m)。所以在一般情况下O(n*m) 肯定是大于 O(n+m) 的,所以通常not exists要比not in查询效率更高。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值