之前一直不知道exists和in的用法与效率,此次的项目中须要用到,因此本身研究了一下。下面是我举两个例子说明二者之间的效率问题。java
前言概述:sql
“exists”和“in”的效率问题,涉及到效率问题也就是sql优化:数据库
1.若子查询结果集比较小,优先使用in。缓存
2.若外层查询比子查询小,优先使用exists。原理是:若匹配到结果,则退出内部查询并将条件标志为true,传回所有结果资料oracle
由于若用in,则oracle会优先查询子查询,而后匹配外层查询,原理是:in无论匹配到匹配不到都所有匹配完毕,匹配相等就返回true,就会输出一条元素.性能
若使用exists,则oracle会优先查询外层表,而后再与内层表匹配优化
也就是:”匹配原则,拿最小记录匹配大记录。也就是遍历的次数越少越好"spa
例子以下:code
1) select * from T_USER1 where exists(select 1 from T_USER2 where T_USER1.jxb_id =T_USER2.jxb_id ) ;blog
T_USER1 数据量小而T_USER2 数据量很是大时,T_USER1 <<T_USER2 时,1) 的查询效率高。
原理解析:以上查询使用了exists语句,sql语句如:select a.* from A a where exists(select 1 from B b where a.id=b.id)
exists()会执行A.length次,它并不缓存exists()结果集,由于exists()结果集的内容并不重要,重要的是结果集中是否有记录,若是有则返回true,没有则返回false.
它的查询过程相似于如下过程:
1 List resultSet=[]; 2 Array A=(select * from A) 3 4 for(int i=0;i<A.length;i++) { //这个循环次数越少越好 5 if(exists(A[i].id) { //执行select 1 from B b where b.id=a.id是否有记录返回 6 resultSet.add(A[i]); 7 } 8 } 9 return resultSet;
当B表比A表数据大时适合使用exists(),由于它没有那么遍历操做,只须要再执行一次查询就行.
如:A表有10000条记录,B表有1000000条记录,那么exists()会执行10000次去判断A表中的id是否与B表中的id相等.
如:A表有10000条记录,B表有100000000条记录,那么exists()仍是执行10000次,由于它只执行A.length次,可见B表数据越多,越适合exists()发挥效果
再如:A表有10000条记录,B表有100条记录,那么exists()仍是执行10000次,还不如使用in()遍历10000*100次,由于in()是在内存里遍历比较,而exists()须要查询数据库,咱们都知道查询数据库所消耗的性能更高,而内存比较很快.
2) select * from T_USER1 where T_USER1.jxb_id in (select T_USER2 .jxb_id from T_USER2 ) ;
T_USER1 数据量很是大而T_USER2数据量小时,T_USER1 >>T_USER2时,2) 的查询效率高。
原理解析:这里有条SQL语句:select * from A where id in(select id from B)
以上查询使用了in语句,in()只执行一次,它查出B表中的全部id字段并缓存起来.以后,检查A表的id是否与B表中的id相等,若是相等则将A表的记录加入结果集中,直到遍历完A表的全部记录;
它的查询过程相似于如下过程
List resultSet=[]; Array A=(select * from A); Array B=(select id from B); for(int i=0;i<A.length;i++) { for(int j=0;j<B.length;j++) { if(A[i].id==B[j].id) { resultSet.add(A[i]); break; } } } return resultSet;
能够看出,当B表数据较大时不适合使用in(),由于它会B表数据所有遍历一次.
如:A表有10000条记录,B表有1000000条记录,那么最多有可能遍历10000*1000000次,效率不好.
再如:A表有10000条记录,B表有100条记录,那么最多有可能遍历10000*100次,遍历次数大大减小,效率大大提高.
=======================================================================================================
详解上面的用法:
exists 用法:
其中 “select 1 from T_USER2 where T_USER1.jxb_id =T_USER2.jxb_id” 至关于一个关联表查询,至关于
“select 1 from T_USER1,T_USER2 where T_USER1.jxb_id=T_USER2.jxb_id”
这种状况下不能单独执行select 1那部分的sql,否则会报语法错误的,这也是使用exists须要注意的地方。
“exists(xxx)”就表示括号里的语句能不能查出记录,它要查的记录是否存在。
所以“select 1”这里的 “1”实际上是可有可无的,换成“*”也没问题,它只在意括号里的数据能不能查找出来,是否存在这样的记录,若是存在,这 1) 句的where 条件成立。
==============================
in 的用法:
“2) select * from T_USER1 where T_USER1.jxb_id in (select T_USER2 .jxb_id from T_USER2 ) ;
这里的“in”后面括号里的语句搜索出来的字段的内容必定要相对应,通常来讲,T1和T2这两个表的a字段表达的意义应该是同样的,不然这样查没什么意义。注意:两个字段名称能够不一样,可是表明的东西必定是同样的才能够。
打个比方:T1,T2表都有一个字段,表示工单号,可是T1表示工单号的字段名叫“ticketid”,T2则为“id”,可是其表达的意义是同样的,并且数据格式也是同样的。这时,用 2)的写法就能够这样:
1 “select * from T1 where T1.ticketid in (select T2.id from T2) ” 2 3 Select name from employee where name not in (select name from student); 4 5 Select name from employee where not exists (select name from student);
第一句SQL语句的执行效率不如第二句。
总结:
经过使用EXISTS,Oracle会首先检查主查询,而后运行子查询直到它找到第一个匹配项,这就节省了时间。
Oracle在执行IN子查询时,首先执行子查询,并将得到的结果列表存放在一个加了索引的临时表中。在执行子查询以前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中之后再执行主查询。
这也就是使用EXISTS比使用IN一般查询速度快的缘由