在上一篇中已经描述了那个神奇的现象,通过SET_SQL_TRACE_IN_SESSION方式,打开会话的SQL_TRACE来跟踪错误发生时到底方式了什么。可是一旦打开SET_SQL_TRACE_IN_SESSION,错误就神奇的消失了。
莫非是由于Oracle监测工具的介入导致了问题的消失。当然除了设置SQL_TRACE外,还有ON ERROR触发器,以及SET EVENTS ERRORSTACK等方法。不过既然发现这些操作可能对问题本身产生影响,那么就先试试别的方向。
上文提到了JAVA程序连接数据库时,同一个SQL,如果表名大写,那么就可以顺利执行,而如果表名小写,则报错。当时认为可能是大小写的问题,不过看JAVA程序中跟踪到的SQL,并不像是这个问题。随后采用的SQL_TRACE的方式,很大程度上也是想看看到底传送到Oracle数据库的SQL到底是什么,是否在表名的地方添加了双引号。不过根据上文给出的trace文件看,数据库中显示的SQL和JAVA程序中捕获的SQL是一样的,并不存在大小写的问题。
那么除了大小写之外,还有什么可能导致这个现象呢。莫非是大小写的改变,导致了SQL语句的重新分析,从而避免了问题。如果是这样的话,在SQL上做些小的改动,也可以到达同样的效果。
测试发现确实如此,将SQL语句select * from usr_action改为select * from usr_action a,或者添加一个WHERE语句select * from usr_action where rownum < 10,问题都不会出现。
这个现象可以确定两个问题,导致问题的原因和表名大小写问题是没有关系的,而和数据库共享池有关系。可以看到,无论是改变大小写,还是改变SQL语句,都会导致这个SQL无法在共享池中找到,这是Oracle会重新分析,从而避免了错误的产生。怀疑设置了SQL_TRACE也是同样的问题,由于启用了SQL_TRACE的功能,可能会强制ORACLE对SQL进行重新分析,导致问题消失。
而如果将SQL语句还原为原来的格式,则这时Oracle会利用共享池中保存的结果,从而导致这个错误的产生。
不过上面的分析虽然合理,但是个疑问没有解释。如果是上面分析的共享池的错误,那么为什么在sqlplus中无法重现这个问题,而只有在JAVA程序中才会出现。假设是共享池保存的SQL分析出现了错误,那么无论是何种方式连接数据库,只要符合SQL重用的标准,都会引发这个问题。
如果说在SQLDEVELOPER中没有在线问题,这并不奇怪,因为DEVELOPER经常会对SQL进行封装,为了更快的得到结果,DEVELOPER会自动的查询实现分页的封装,使得用户可以很快的获取到第一屏的结果。但是SQLPLUS就没有道理模拟不出这个错误了。
再次观察JAVA程序的SQL语句,结果发现了问题的关键。原来JAVA程序中原始的SQL语句在语句的最后还包括了一个空格:‘select * from usr_action ’。这个空格是为了随后添加WHERE语句方法而预留的。而通过JAVA程序中获取的SQL很难发现这个空格的存在,这就是一直在SQLPLUS中无法模拟错误的原因:
$ sqlplus tjsq_trade SQL*Plus: Release 10.2.0.3.0 – Production on Wed Mar 18 10:12:02 2009 Copyright (c) 1982, 2006, Oracle. All Rights Reserved. Enter password: Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 – 64bit Production With the Partitioning, OLAP and Data Mining options SQL> set pages 100 lines 120 SQL> set autot trace SQL> select * from usr_action; 594 rows selected. Execution Plan ———————————————————- Plan hash value: 1947357366 ——————————————————————————– | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ——————————————————————————– | 0 | SELECT STATEMENT | | 594 | 43956 | 4 (0)| 00:00:01 | | 1 | TABLE ACCESS FULL| USR_ACTION | 594 | 43956 | 4 (0)| 00:00:01 | ——————————————————————————– Statistics ———————————————————- 0 recursive calls 0 db block gets 46 consistent gets 0 physical reads 0 redo size 46776 bytes sent via SQL*Net to client 921 bytes received via SQL*Net from client 41 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 594 rows processed SQL> select * from usr_action ; select * from usr_action * ERROR at line 1: ORA-00942: table or view does not exist SQL> select * from usr_action ; 594 rows selected. Execution Plan ———————————————————- Plan hash value: 1947357366 ——————————————————————————– | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ——————————————————————————– | 0 | SELECT STATEMENT | | 594 | 43956 | 4 (0)| 00:00:01 | | 1 | TABLE ACCESS FULL| USR_ACTION | 594 | 43956 | 4 (0)| 00:00:01 | ——————————————————————————– Statistics ———————————————————- 1 recursive calls 0 db block gets 46 consistent gets 0 physical reads 0 redo size 46776 bytes sent via SQL*Net to client 921 bytes received via SQL*Net from client 41 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 594 rows processed |
可以看到,利用TJSQ_TRADE连接数据库后,第一个查询不带空格,因此可以顺利的执行,而第二个查询后面带了一个空格,这个和JAVA程序中的SQL完全匹配,于是重现了问题。而最后一个SQL后包含了两个空格,也是可以顺利执行的。
现在问题可以在SQLPLUS中重现,说明问题和JAVA程序没有关系。导致问题的原因应该和数据库的共享池有关。
其实到现在为止,问题已经不难解决,如果不出意外,只需要刷新一下共享池就这个问题就会消失。
不过现在还没有到解决问题的时候,因为导致问题的真正原因还不清楚。就算是Oracle的bug,这个bug也不会凭空出现,总有什么诱因导致了bug的产生。如果现在只是简单的刷新共享池,问题虽然消失了,但是查找导致问题真正原因的线索也消失了。为了确定导致BUG产生的原因,使得以后可以避免问题的产生,现在不妨在保留这个问题一段时间。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
作者
相关推荐
-
甲骨文自治数据库亮相 带来云计算新希望
早前甲骨文还不在云计算公司之列,而现在该公司正在迅速弥补其失去的时间。甲骨文的云计算核心是甲骨文自治数据库(O […]
-
2017年12月数据库流行度排行榜 定格岁末排名瞬间
数据库知识网站DB-engines最近更新的2017年12月份数据库流行度排名情况是否能提供更多的看点呢?TechTarget数据库网站将与您分享12月份的榜单排名情况,让我们拭目以待。
-
2017年11月数据库流行度排行榜 半数以上数据库积分减少
数据库知识网站DB-engines更新了2016年11月份的数据库流行度排行榜。TechTarget数据库网站将与您一同关注11月份的榜单排名情况。
-
控制合约 不再畏惧Oracle
许多公司都与Oracle有无限制授权协议,他们害怕离开这个协议,所以就证明他们在使用Oracle的软件,即使因为需求单独购买部分授权许可也可能总体是省钱的。