现在的位置: 首页 > 综合 > 正文

oracle中的exists和in

2012年04月19日 ⁄ 综合 ⁄ 共 1497字 ⁄ 字号 评论关闭

有时候会将一列和一系列值相比较。最简单的办法就是在 where 子句中使用子查询。在
where子句中可以使用两种格式的子查询。 
第一种格式是使用IN操作符: 
... where column in(select * from ... where ...);  
第二种格式是使用EXIST操作符:
... where exists (select 'X' from ...where ...);  
 
我相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第
一种格式的效率高。在 Oracle中可以几乎将所有的 IN操作符子查询改写为使用 EXISTS的子查
询。

第二种格式中, 子查询以‘ select 'X' 开始。运用 EXISTS 子句不管子查询从表中抽取什么数
据它只查看 where 子句。 这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在
where 语句中使用的列存在索引)。相对于 IN 子句来说, EXISTS 使用相连子查询,构造起来要
比 IN 子查询困难一些。

通过使用 EXIST , Oracle 系统会首先检查主查询,然后运行子查询直到它找到第一个匹配
项,这就节省了时间。 Oracle 系统在执行 IN 子查询时,首先执行子查询,并将获得的结果列表
存放在在一个加了索引的临时表中。在执行子查询之前, 系统先将主查询挂起,待子查询执行完
毕,存放在临时表中以后再执行主查询。这也就是使用 EXISTS 比使用 IN 通常查询速度快的原
因。

同时应尽可能使用 NOT EXISTS 来代替 NOT IN ,尽管二者都使用了 NOT (不能使用索引
而降低速度), NOT EXISTS 要比 NOT IN 查询效率更高。

但时下面的例外还要看一下:

in适合内外表都很大的情况,exists适合外表结果集很小的情况。
=====================================
今天市场报告有个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确实是要根据表的数据量来决定使用。

 

抱歉!评论已关闭.