查看: 24785|回复: 27

[转载] EXISTS、IN、NOT EXISTS、NOT IN的区别(ZT)

[复制链接]
论坛徽章:
101
生肖徽章:猴
日期:2007-09-26 12:35:50复活蛋
日期:2011-07-08 14:26:172010广州亚运会纪念徽章:手球
日期:2011-05-09 10:15:122010广州亚运会纪念徽章:排球
日期:2011-04-13 11:57:232011新春纪念徽章
日期:2011-02-18 11:43:332010广州亚运会纪念徽章:射箭
日期:2011-01-21 14:58:57ITPUB9周年纪念徽章
日期:2010-10-08 09:28:522010广州亚运会纪念徽章:自行车
日期:2010-09-17 10:43:02铁扇公主
日期:2010-07-28 08:46:33ITPUB元老
日期:2009-05-12 13:23:24
跳转到指定楼层
1#
发表于 2008-2-2 13:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
EXISTS、IN、NOT EXISTS、NOT IN的区别:


in适合内外表都很大的情况,exists适合外表结果集很小的情况。
exists 和 in 使用一例
===========================================================
今天市场报告有个sql及慢,运行需要20多分钟,如下:
update p_container_decl cd
set cd.ANNUL_FLAG='0001',ANNUL_DATE = sysdate
where exists(
select 1
from (
select tc.decl_no,tc.goods_no
from p_transfer_cont tc,P_AFFIRM_DO ad
where tc.GOODS_DECL_NO = ad.DECL_NO
and ad.DECL_NO = 'sssssssssssssssss'
) a
where a.decl_no = cd.decl_no
and a.goods_no = cd.goods_no
)
上面涉及的3个表的记录数都不小,均在百万左右。根据这种情况,我想到了前不久看的tom的一篇文章,说的是exists和in的区别,
in 是把外表和那表作hash join,而exists是对外表作loop,每次loop再对那表进行查询。
这样的话,in适合内外表都很大的情况,exists适合外表结果集很小的情况。

而我目前的情况适合用in来作查询,于是我改写了sql,如下:
update p_container_decl cd
set cd.ANNUL_FLAG='0001',ANNUL_DATE = sysdate
where (decl_no,goods_no) in
(
select tc.decl_no,tc.goods_no
from p_transfer_cont tc,P_AFFIRM_DO ad
where tc.GOODS_DECL_NO = ad.DECL_NO
and ad.DECL_NO = ‘ssssssssssss’
)

让市场人员测试,结果运行时间在1分钟内。问题解决了,看来exists和in确实是要根据表的数据量来决定使用。

请注意not in 逻辑上不完全等同于not exists,如果你误用了not in,小心你的程序存在致命的BUG:


请看下面的例子:
create table t1 (c1 number,c2 number);
create table t2 (c1 number,c2 number);

insert into t1 values (1,2);
insert into t1 values (1,3);
insert into t2 values (1,2);
insert into t2 values (1,null);

select * from t1 where c2 not in (select c2 from t2);
no rows found
select * from t1 where not exists (select 1 from t2 where t1.c2=t2.c2);
c1 c2
1 3

正如所看到的,not in 出现了不期望的结果集,存在逻辑错误。如果看一下上述两个select语句的执行计划,也会不同。后者使用了hash_aj。
因此,请尽量不要使用not in(它会调用子查询),而尽量使用not exists(它会调用关联子查询)。如果子查询中返回的任意一条记录含有空值,则查询将不返回任何记录,正如上面例子所示。
除非子查询字段有非空限制,这时可以使用not in ,并且也可以通过提示让它使用hasg_aj或merge_aj连接。
论坛徽章:
33
劳斯莱斯
日期:2013-08-08 14:01:23三菱
日期:2013-09-28 10:16:06一汽
日期:2013-11-19 17:01:11凯迪拉克
日期:2013-12-07 17:11:282014年新春福章
日期:2014-02-18 16:42:02马上有房
日期:2014-02-18 16:42:02itpub13周年纪念徽章
日期:2014-09-27 14:20:21itpub13周年纪念徽章
日期:2014-10-08 15:13:38懒羊羊
日期:2015-03-04 14:52:112015年新春福章
日期:2015-03-06 11:58:18
2#
发表于 2008-2-2 14:43 | 只看该作者

不错的实例

使用道具 举报

回复
论坛徽章:
194
红宝石
日期:2014-05-09 08:24:37萤石
日期:2014-01-03 10:25:39奥运会纪念徽章:羽毛球
日期:2008-07-01 10:46:06奥运会纪念徽章:马术
日期:2008-07-07 17:43:24奥运会纪念徽章:射箭
日期:2008-07-25 18:07:39奥运会纪念徽章:皮划艇激流回旋
日期:2008-07-30 10:02:57奥运会纪念徽章:花样游泳
日期:2008-09-26 13:02:43奥运会纪念徽章:排球
日期:2008-12-03 11:23:272010新春纪念徽章
日期:2010-01-04 08:33:082010年世界杯参赛球队:澳大利亚
日期:2010-02-26 11:08:44
3#
发表于 2008-2-2 14:43 | 只看该作者
这个仅仅是一些bug,并不能说明问题,在10g下测试有这些问题吗?
我个人觉得主要是查询转换,看oracle是否选择可以的执行计划。

使用道具 举报

回复
论坛徽章:
14
生肖徽章2007版:蛇
日期:2008-03-24 17:16:29生肖徽章2007版:猴
日期:2009-02-09 15:03:45生肖徽章2007版:猪
日期:2009-03-16 10:15:58生肖徽章2007版:龙
日期:2009-03-27 12:02:52生肖徽章2007版:虎
日期:2009-04-15 17:44:55
4#
发表于 2008-2-2 16:10 | 只看该作者
原帖由 lfree 于 2008-2-2 14:43 发表
这个仅仅是一些bug,并不能说明问题,在10g下测试有这些问题吗?
我个人觉得主要是查询转换,看oracle是否选择可以的执行计划。


对关键是看执行计划,让计划走自己期望的路线,尽快排除最大量的数据,尽量走索引

使用道具 举报

回复
论坛徽章:
0
5#
发表于 2008-2-2 16:12 | 只看该作者



select * from danwei t where t.bumenid not in(select c.bumenid from ceshi c);
我这个到没有问题可以查询

我的是9i
LZ 所说的 not in 和 not exists 区别到是挺不错的 ,还有int 和exists 的区别

单从 SQL来看我觉得,只是条件不同而已,,如果你用not exists 你就得具体指出关联来
但是
select * from danwei t where t.bumenid not in(select c.bumenid from ceshi c where c.bumenid=t.bumenid);
这样我也可以运行哦!!!

使用道具 举报

回复
论坛徽章:
2
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:442008新春纪念徽章
日期:2008-02-13 12:43:03
6#
发表于 2008-2-7 15:51 | 只看该作者
首先,版主(lfree)就是版主,果然有见地。

对于In, exists 和 not in, not exists, 在9i 和 10g中,如果关联字段在子查询中不为null, oracle 的处理方式是基本一样的,
In, exists, oracle server会尽量转换成semi join
not in, not exists oracle server会尽量转换成anti join
但是对于 not exists, 9i处理的时候有个bug, 那就是9i好像不会主动转换成anti join,但是可以将not in 主动转换成anti join

我想这就是楼主的遇到的问题的原因吧。

对于Null引起的not in 和 not exists的区别,主要是由于null 运算引起的
select * from t1 where c2 not in (select c2 from t2);
oracle server需要运算 t1.c2 <> t2.c2, 如果t2.c2存在null, 那么t1.c2 <> t2.c2 ==> null,即导致条件不满足,
所以no row selected

[ 本帖最后由 darcy07 于 2008-2-7 16:04 编辑 ]

使用道具 举报

回复
论坛徽章:
87
2015年新春福章
日期:2015-03-06 11:58:182010广州亚运会纪念徽章:轮滑
日期:2010-09-23 17:19:212010年世界杯参赛球队:乌拉圭
日期:2010-07-14 17:54:242010年世界杯参赛球队:美国
日期:2010-06-30 13:13:582010年世界杯参赛球队:墨西哥
日期:2010-06-25 12:49:452010年世界杯参赛球队:墨西哥
日期:2010-04-05 10:23:502010新春纪念徽章
日期:2010-03-01 11:06:232010新春纪念徽章
日期:2010-01-04 08:33:08生肖徽章2007版:龙
日期:2009-11-12 16:31:13参与WIN7挑战赛纪念
日期:2009-11-09 11:50:09
7#
发表于 2008-2-8 18:43 | 只看该作者
不错
不顶不行啊

使用道具 举报

回复
论坛徽章:
2
数据库板块每日发贴之星
日期:2008-02-11 01:03:562008新春纪念徽章
日期:2008-02-13 12:43:03
8#
发表于 2008-3-8 23:38 | 只看该作者
顶上.......

使用道具 举报

回复
论坛徽章:
97
ITPUB十周年纪念徽章
日期:2011-11-01 16:24:04
9#
发表于 2008-3-9 00:13 | 只看该作者
好,收藏

使用道具 举报

回复
论坛徽章:
0
10#
发表于 2008-3-9 21:05 | 只看该作者
顶 特别是关于not in中子查询有null的,以前一直没注意!提醒我了~

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表