有个空间

有个标题

ORA-01795,in和exists性能

今天,客户那边出来一个问题,出现"ORA-01795:列表中的最大表达式数为1000 "异常。

sql文是这样的:
1 select ENAME
2   from  VIP_EMP
3  where GROUP_ID = '0001'
4    and SUBGROUP_ID = '000101'
5    and VIPNO  in
6        (select EMPNO
7           from EMP
8          where EMPTYPE = 'VIP')

调查后发现,在"PLSQL Developer"和"sqldeveloper"中直接运行时,都不会报错,虽然上面子查询的记录大于1000条。
然后,尝试将子查询改成拼接一个大于1000项的数组,结果如愿出现"ORA-01795"异常。
猜想,开发这边的数据库可能将上述sql文优化了,但客户数据库没有经编译器优化,所以出异常。

可能优化成了以下的形式:
1 select e1.ENAME from VIP_EMP e1, (select EMPNO from EMP where EMPTYPE= 'VIP') e2 
2    where e1.VIPNO = e2.EMPNO;
2        and e1.GROUP_ID = '0001'
2        and e1.SUBGROUP_ID = '000101'

最终,个人修改意见是,修改成两张表链结的形式,即优化以后的样子。这样修改,性能先不管,至少不会出现异常。

还有个尾巴留下来了,就是In的性能问题。现将网上查到的东西贴出来。

1.in和exists的性能差别

 在where子句中可以使用两种格式的子查询。

第一种格式是使用IN操作符,第二种格式是使用EXIST操作符。

修改的exists形式:

1  select e1.ENAME
2    from VIP_EMP e1
3   where e1.GROUP_ID = '0001'
4     and e1.SUBGROUP_ID = '000101'
5     and exists (select 0
6            from EMP e2
7           where e2.EMPTYPE = 'VIP'
8             and e2.EMPNO = e1.VIPNO)

用第一种:Oracle系统在执行IN子查询时,首先执行 子查询,并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查 询。

用第二种:通过使用 EXIST,Oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。这也就是使用EXISTS比使用IN通常查询速度快的原因。子查询以‘select 'X'开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定 在where语句中使用的列存在索引)。

相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。


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

比较一致的看法是:为了确定在基于规则的最优化中,哪一种子句性能更佳,不妨考虑一下,与外部查询相比,内部查询会返回多少行记录。许多情况下,EXISTS的表现更突出, 这是因为,它需要你指定一个加入条件,这就可以调用一个INDEX扫描。尽管如此,如果该查询的结果很小的话,IN常常表现得更好。你通常都愿意运行那些 能首先返回较少的结果的查询。

千言万语总结成一句话:如果内表大,外表小用exists或not exists,反之用in或not in;

个人推荐还是用两张表链结的形式,直观简单,至少不会出现ORA-01795异常


posted on 2009-09-07 13:54 游雯 阅读(4951) 评论(0)  编辑  收藏 所属分类: Java技术


只有注册用户登录后才能发表评论。


网站导航: