2012-01-05 83 views
12

我有一个oracle stored proc需要从我的Java程序调用。我曾使用CallableStatement将参数传递给存储过程。我正在使用oracle瘦驱动程序(在web逻辑服务器中针对相关的jndi条目进行配置)。此存储过程没有任何OUT值。这个存储过程接受一个数值,并根据接收到的值在数据库中做很多更新。的PreparedStatement,CallableStatement的和性能考虑

我得到一个连接对象,然后调用这个循环存储过程(20次传递20号)。当我直接从oracle客户端调用这个存储过程时,执行会在2-3秒内完成。但是,这种行为是不可预测的从我的java代码。有些电话甚至需要30-40秒才能完成。

我试图使用PreparedStatement而不是CallableStatement,并可以看到边际性能的改善(尽管行为仍然不一致)。

  1. 是否确定在我的情况下使用PreparedStatement,而不是CallableStatement鉴于storedproc没有任何OUT参数?
  2. 没有任何理由为什么PreparedStatement具有一定的性能增益超过CallableStatement或者是它的东西,我可能会观察是否有误?
  3. 解决这个性能问题有更好的方法吗?
+3

你能后的代码?或者,确认每次迭代都没有建立连接(而不是重复使用一个连接),并确认每次迭代都没有调用'conn.prepareCall()'(而不是只有'.setInt() )'和'.execute()'在循环中)。 – Matt 2012-01-05 18:56:36

+1

您不止一次地调用存储过程,对吗?你有没有尝试过使用批量调用? http://docs.oracle.com/javase/1.3/docs/guide/jdbc/getstart/callablestatement.html请参阅7.1.3 – 2012-01-05 18:57:22

+1

为什么不尝试匿名PL/SQL块(开始...调用过程...调用过程......结束;)调用你的存储过程20次,并使用匿名块对数据库进行一次调用。 – GriffeyDog 2012-01-05 19:05:57

回答

8

从你的评论,你有你的prepareCall循环中。准备好的语句(和可调用语句)的一个优点是可以准备一次,然后换出参数中传递的值;每次呼叫准备时都会有开销,所以如果您可以将呼叫置于循环之外,您可能会发现运行时间减少。您可能会发现关闭AutoCommit也有帮助,因为每次提交都会有开销。

conn.setAutoCommit(false); 
CallableStatement stmt = conn.prepareCall(sql); 
while(true) { 
    stmt.setInt(1, value); 
    stmt.execute(); 
} 
conn.commit(); 
conn.setAutoCommit(true); 

conn.setAutoCommit(true)没有提交,但我发现它更清晰明确)。

+0

谢谢马特,我明白了很多,我相信这会修复我的我会尝试这个和塞尔吉奥的建议。欣赏你的时间和帮助:) – 2012-01-05 19:19:24

+0

嗨马特 - 尝试了你和塞尔吉奥建议的方法,但它通过我的java代码执行时仍然很慢。 – 2012-01-06 07:39:08

+0

更新:我猜测程序本身现在非常慢,当我尝试直接使用我的oracle客户端访问该过程时 - 每个数字大约需要2分钟。这在一天中的不同时间表现不同,这是我需要调查的东西。感谢你的帮助。 – 2012-01-06 07:44:18

1

您不应该考虑使用批次吗?

conn.setAutoCommit(false); 
CallableStatement stmt = conn.prepareCall(sql); 
while(true) { 
    stmt.setInt(1, value); 
    stmt.addBatch(); 
} 
stmt.executeBatch() 
conn.commit();