2012-01-05 82 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();