oracle 中not in 与 not exists 执行效率到底谁高谁低?

阅读更多
网上相关信息很多很多,到底not in 与  not  exists谁的效率高,说实话,我也不知道!
select  count(1)  from ba_ry_jbxx a  where  not  exists   (select b.gmsfzh from ba_ry_zgkssh  b  where    a.gmsfzh = b.gmsfzh);
select  count(1)  from ba_ry_jbxx a  where  a.gmsfzh not  in    (select b.gmsfzh from ba_ry_zgkssh  b );
以下针对这两条语句分析:

说到比较,首先得有共同点才会去比较,共同点就是:都可以查询a表中的gmsfzh字段的值不在b表中的gmsfzh字段里的记录数。
前提条件是首先得保证这两个语句查询的数据的正确性,才可以进行效率的比较。
(1)当b表中的gmsfzh字段有空值时,用not in查询结果为0.所以这两个语句比较效率就没有任何意义了!就直接用not exists!
(2)当a表中的gmsfzh字段有空值时,查询结果固然也不一样,用 not  exists 查询的记录数会大于用not  in的记录数,因为 not  exists把空值也
作为查询结果了,而not  in不把空值作为结果。
(
至于为什么,我的理解是:因为not  exists会关联a.gmsfzh = b.gmsfzh一下,除了关联上的数据其他的在a表中剩下的记录都认为不在b表中,因为空值肯定是关联不上的,
所以就认为空值不在b表中。
而为什么用not in时,a表中的空值就不算在查询结果内呢!因为oracle就这么规定的)

所以当a表中的gmsfzh字段有空值时,因为查询结果都不一样,你觉得哪个查询结果是正确的,固然就用哪个!

如果排除两个表的空值的问题,或者说a表中的空值并不影响查询结果的正确性时,接下来可以考虑not in 和not  exists的执行效率问题了:

数据量情况:a表 100条记录, b表 70000条记录,执行以下两语句:
select  count(1)  from ba_ry_jbxx a  where  not  exists   (select b.gmsfzh from ba_ry_zgkssh  b  where    a.gmsfzh = b.gmsfzh);
select  count(1)  from ba_ry_jbxx a  where  a.gmsfzh not  in    (select b.gmsfzh from ba_ry_zgkssh  b );
当两个表都为gmsfzh字段建了索引的情况下
实测结果如下:
用not  exists,耗时0.015秒。
用not  in,耗时50.641秒。
这差距还真有点大。。。
毫无疑问,用not  exists走索引了,而not  in 并不走索引。

当删除两个表的索引之后:
实测结果如下:
用not  exists,耗时50秒。
用not  in,耗时 50.875秒,此时not  exists和not in 几乎差不多。

数据量不变,反过来测试:
select  count(1)  from ba_ry_zgkssh b  where  not  exists   (select a.gmsfzh from ba_ry_jbxx  a  where    b.gmsfzh = a.gmsfzh);
select  count(1)  from ba_ry_zgkssh b  where  b.gmsfzh not  in    (select a.gmsfzh from ba_ry_jbxx  a );
无索引:
用not  in,耗时 3.703秒.
用not  exists,耗时3.641秒。(此时至少说明,无索引的情况下,b表数据量远远大于a表时,not in与not exists效率差不多)

建完索引后:
用not  in,耗时 3.937秒.
用not  exists,耗时0.813秒。

以上数据测试可见,索引的重要性。


我总觉得,not in既然存在,肯定有他存在的道理。
测试这么多,至少证明,有索引的情况下,多数时候not exists完虐not  in的执行效率。
现在我纠结的问题就是,到底什么情况下not  in效率要高于not exists? 还请高人留言指点一下。

你可能感兴趣的:(oracle,not,in和not,exists,执行效率,索引)