今天,客户那边出来一个问题,出现"
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异常