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')
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'
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)
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子查詢困難一些。
比較一致的看法是:為了確定在基于規則的最優化中,哪一種子句性能更佳,不妨考慮一下,與外部查詢相比,內部查詢會返回多少行記錄。許多情況下,EXISTS的表現更突出, 這是因為,它需要你指定一個加入條件,這就可以調用一個INDEX掃描。盡管如此,如果該查詢的結果很小的話,IN常常表現得更好。你通常都愿意運行那些 能首先返回較少的結果的查詢。
千言萬語總結成一句話:如果內表大,外表小用exists或not exists,反之用in或not in;
個人推薦還是用兩張表鏈結的形式,直觀簡單,至少不會出現ORA-01795異常
posted on 2009-09-07 13:54 游雯 閱讀(4959) 評論(0) 編輯 收藏 所屬分類: Java技術