设为首页 收藏本站
查看: 645|回复: 0

[经验分享] oracle in和exists的详解分析

[复制链接]

尚未签到

发表于 2016-7-28 09:52:33 | 显示全部楼层 |阅读模式
  首先我要感谢aa和Liu Xing帮我发现了我日志中的错误。之前比较粗心,把3条SQL语句写成一样的了,对于给读者造成的麻烦,我深表抱歉。

今天我把原文做了修订,为了对得起读者对我的关注,我重新深入的研究了这个问题,在后面,我会把来龙去脉写清楚。

问题:

语句1 :

Select * from table1A where A.col1 not in( select col1 from table2B)

  转载注明出处:http://x- spirit.iyunv.com/、http: //www.blogjava.net/zhangwei217245/
如果这样,本来应该有一条数据,结果没有。
如果我改写成这样:

语句2 :

select * from table1 A where not exists (SELECT * FROMtable2 B whereB.col1 = A.col1)
  结果就正确,有一条数据显示。
转载注明出处:http://x- spirit.iyunv.com/、http: //www.blogjava.net/zhangwei217245/

经过一番搜索,原以为是子查询结果集太大的原因。

后来有网上强人指点:子查询里面有空集。即子查询的结果集里面有NULL的结果。

把查询语句修改成:

语句3 :

Select * from table1A where A.col1 not in( select col1 from table2B where B.col1 is not null )

  
果然就查出来了。而且一点不差。。。厉害阿~~~



下面是针对本文题的分析:

1。 首先来说说Oracle中的NULL。

Oracle中的NULL代表的是无意义,或者没有值。将NULL和其他的值进行逻辑运算,运算过程中,NULL的表现更象是FALSE。
下面请看真值表:
AND NULLOR NULL
TRUENULLTRUE
FALSEFALSENULL
NULLNULLNULL
  
另外,NULL和其他的值进行比较或者算术运算(<、>、=、!=、+、-、*、/),结果仍是NULL。

如果想要判定某个值是否为NULL,可以用IS NULL或者IS NOT NULL。

2. 再来说说Oracle中的IN。

in是一个成员条件, 对于给定的一个集合或者子查询,它会比较每一个成员值。
IN功能上相当于 =ANY 的操作,而NOT IN 功能上相当于 !=ALL 的操作。
IN在逻辑上实际上就是对给定的成员集合或者子查询结果集进行逐条的判定,例如:
SELECT * FROMtable1A WHEREA.col1 in( 20 , 50 , NULL);
  实际上就是执行了
SELECT * FROMtable1A WHEREA.col1 = 20 ORA.col1 = 50 ORA.col1 = NULL ;
  这样,根据NULL的运算特点和真值表,我们可以看出,上边这个WHERE 字句可以被简化(如果返回NULL则无结果集返回,这一点和FALSE是一样的)为
WHERE A.col1= 20 ORA.col1 = 50
  也就是说,如果你的table1中真的存在含有NULL值的col1列,则执行该语句,无法查询出那些值为null的记录。

再来看看NOT IN。根据逻辑运算关系,我们知道,NOT (X=Y OR N=M) 等价于 X!=Y AND N!=M,那么:
SELECT * FROMtable1A WHEREA.col1 not in ( 20 , 50 , NULL )
  等价于
SELECT * FROMtable1A WHEREA.col1 != 20 ANDA.col1 != 50 ANDA.col1 != NULL
  根据NULL的运算特性和真值表,该语句无论前两个判定条件是否为真,其结果一定是NULL或者FALSE。故绝对没有任何记录可以返回。

这就是为什么语句1查不到应有结果的原因。当然,如果你用NOT IN的时候,预先在子查询里把NULL去掉的话,那就没问题了,例如语句3
有些童鞋可能要问了:那如果我想把A表里面那些和B表一样col1列的值一样的记录都查出来,即便A、B两表里面的col1列都包括值为NULL的记录的话,用这一条语句就没办法了吗?

我只能很遗憾的告诉你,如果你想在WHERE后面单纯用IN 似乎不太可能了,当然,你可以在外部的查询语句中将NULL条件并列进去,例如:
SELECT * FROMtable1A WHEREA.col1 in( SELECT B.col1 FROM table2B) OR A.col1 IS NULL ;
  
转载注明出处:http://x- spirit.iyunv.com/、http: //www.blogjava.net/zhangwei217245/

3. 最后谈谈EXISTS。

有人说EXISTS的性能比IN要好。但这是很片面的。我们来看看EXISTS的执行过程:
select * fromt1 where exists (select * from t2where t2.col1 = t1.col1 )
  相当于:
for x in ( select * from t1)
loop
if (exists ( select * fromt2 where t2.col1 = x.col1 )
then
OUTPUTTHERECORD in x
end if
end loop
  转载注明出处:http://x- spirit.iyunv.com/、http: //www.blogjava.net/zhangwei217245/
也就是说,EXISTS语句实际上是通过循环外部查询的结果集,来过滤出符合子查询标准的结果集。于是外部查询的结果集数量对该语句执行性能影响最大,故如果外部查询的结果集数量庞大,用EXISTS语句的性能也不一定就会好很多。
转载注明出处:http://x- spirit.iyunv.com/、http: //www.blogjava.net/zhangwei217245/
当然,有人说NOT IN是对外部查询和子查询都做了全表扫描,如果有索引的话,还用不上索引,但是NOT EXISTS是做连接查询,所以,如果连接查询的两列都做了索引,性能会有一定的提升。
当然至于实际的查询效率,我想还是具体情况具体分析吧。


那么我们不妨来分析一下语句2为什么能够的到正确的结果吧:

语句2是这样的:
select * from table1 A where not exists (SELECT B.col1 FROM table2 B where B.col1 = A.col1)
  
实际上是这样的执行过程:
for x in ( select * from table1 A )
loop
if (notexists ( select * fromtable2 B whereB.col1 = x.col1 )
then
OUTPUTTHERECORD in x
end if
end loop
  转载注明出处:http://x- spirit.iyunv.com/、http: //www.blogjava.net/zhangwei217245/
由于表A中不包含NULL的记录,所以,遍历完表A,也只能挑出表A中独有的记录。

这就是为什么语句2 能够完成语句3 的任务的原因。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-250524-1-1.html 上篇帖子: Oracle百万记录sql语句优化技巧 下篇帖子: Oracle DBA 基础之 DDL 语句
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表