SQL in与exists相关性能问题总结

SQL  in与exists相关性能问题总结

  • in 和 exists     

     in 和 exists的是DBA或开发人员日常工作学习中常用的基本运算符,今天我就这两个所带来的性能问题进行分析总结,方便自己与他人的后续学习与工作。

    先来了解in 和 exists的性能区别: 如果主查询中的表较大且又有索引,子查询得出的结果集记录较少时,应该用in;反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists。

举例说明: select * from A where A.ID in(select B.ID from B )

                  select * from A  where exists(select 1 from B where A.ID=B.ID)

  其中,第一句in字句使用的是外层A表的索引,括号中的B全表扫描,所以,当A表巨大而B表很小的时候,此时性能较高,反之性能很差;

                第二句exists字句中使用的是内层B表的索引,外面A全表扫描,所以,当B表巨大而A表很小的时候,此时性能较高,反之性能很差。

     区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是in,那么先执行子查询,再以in为驱动表,去查找外层表中符合要求的记录,所以我们会以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了。

a)         in的执行顺序:

1.首先执行一次子查询,子查询先产生结果集;

2. 然后主查询再去结果集里去找符合要求的字段列表去.符合要求的输出,反之则不输出。

b)        exists的执行顺序:

1.首先执行一次外部查询;

2.对于外部查询中的每一行分别执行一次子查询,而且每次执行子查询时都会引用外部查询中当前行的值;

3.使用子查询的结果true或false来确定外部查询的结果集。

例如:表A(小表),表B(大表)
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列的索引。

exists适合外表结果集很小的情况;in适合外表结果集很大,而内表结果集较小的情况。

  •  not in 和not exists

     这里首先要说,not in 逻辑上不完全等同于not exists,当子查询中返回的任意一条记录含有空值,则not in查询将不返回任何记录;当子查询字段有非空限制,这时可以使用not in。

1、对于not exists查询,内表存在空值对查询结果没有影响;对于not in查询,内表存在空值将导致最终的查询结果为空。

2、对于not exists查询,外表存在空值,存在空值的那条记录最终会输出;对于not in查询,外表存在空值,存在空值的那条记录最终将被过滤,其他数据不受影响。

3、解释为什么not in语句比not exists语句效率差这么多(not in 不走索引):

     not exists语句很显然就是一个简单的两表关联,内表与外表中存在空值本身就不参与关联;

     not exists的执行顺序是:在表中查询,是根据索引查询的,如果存在就返回true,如果不存在就返回false,不会每条记录都去查询。

     not in的执行顺序是:是在表中一条记录一条记录的查询(查询每条记录)符合要求的就返回结果集,不符合的就继续查询下一条记录,直到把表中的记录查询完。也就是说为了证明找不到,所以只能查询全部记录才能证明,并没有用到索

 

 

 

原文地址:https://www.cnblogs.com/syforacle/p/5820624.html