2010-05-27 85 views
17

我們正在運行java6/hibernate/c3p0/postgresql堆棧。 我們的JDBC驅動程序是8.4-701.jdbc3我應該激活c3p0語句池嗎?

我對準備語句有幾個問題。我已閱讀 優秀文檔約Prepared Statements

但我仍然有一個問題,如何配置PostgreSQL的c3p0。

目前,我們有

c3p0.maxStatements = 0 
c3p0.maxStatementsPerConnection = 0 

在我的理解中準備的語句和語句池是兩個不同的東西:

我們休眠堆棧使用準備好的語句。 Postgresql緩存 執行計劃。下一次使用相同的語句時,postgresql會重用 執行計劃。這可以節省DB中的時間計劃語句。

此外,c3p0可以緩存「java.sql.PreparedStatement」 的java實例,這意味着它正在緩存java對象。所以當使用
c3p0.maxStatementsPerConnection = 100時,它會緩存至多100個不同的對象的
對象。它節省了創建對象的時間,但這與postgresql數據庫及其準備的語句無關 。

,對嗎?

當我們使用約100個不同的語句我會成立 c3p0.maxStatementsPerConnection = 100

但C3P0文檔說在c3p0 known shortcomings

語句池的開銷 太高。對於不支持 的驅動程序,執行 PreparedStatements的重要預處理,共用 開銷超過了任何節省。 默認情況下,語句池關閉爲 。如果您的驅動程序執行 預處理PreparedStatements, ,特別是如果它通過具有 RDBMS的IPC執行,您可能會看到 明顯的性能增益, 將語句池合併。 (通過將配置屬性 maxStatements或 maxStatementsPerConnection設置爲大於零的值 來執行此操作 )。

所以:用c3p0和Postgresql激活maxStatementsPerConnection是否合理? 激活它有沒有真正的好處?

親切的問候 Janning

回答

23

我不記得的副手,如果Hibernate的實際存儲的PreparedStatement實例本身,或依賴於連接提供商重用他們。(BatcherImpl的快速掃描表明,如果連續多次執行相同的SQL,它會重用最後一個PreparedStatement)

我認爲c3p0文檔試圖做的一點是,對於許多JDBC驅動程序,PreparedStatement不是' t很有用:一些驅動程序最終只會在客戶端拼接參數,然後將構建的SQL語句傳遞到數據庫。對於這些驅動程序,PreparedStatements根本沒有優勢,任何重複使用的努力都是浪費的。 (Postgresql JDBC FAQ說這是在sever協議版本3之前的Postgresql的情況,並且在documentation中有更詳細的信息)。

對於確實有效處理PreparedStatements的驅動程序,仍然可能需要實際重用PreparedStatement實例才能獲得任何好處。例如,如果驅動程序實現:

  • 各種Connection.prepareStatement(SQL) - 創建一個服務器端的聲明
  • PreparedStatement.execute(..)等等 - 執行服務器端聲明
  • PreparedStatement.close () - 取消分配服務器端的聲明

鑑於此,如果應用程序總是打開一個事先準備好的聲明,執行一次,然後再次關閉它,有仍然沒有好處;事實上,這可能會更糟,因爲現在可能會有更多的往返行程。所以應用程序需要掛在PreparedStatement實例上。當然,這會導致另一個問題:如果應用程序掛起太多,並且每個服務器端語句都會消耗一些資源,那麼這會導致服務器端問題。在有人直接使用JDBC的情況下,這可能需要手動管理 - 一些語句已知是可重用的,因此已準備就緒;有些不是,只是使用暫時的Statement實例。 (這是跳過預處理語句的其他好處:處理參數轉義)

所以這就是爲什麼c3p0和其他連接池也準備好語句緩存 - 它允許應用程序代碼避免處理所有這些。這些語句通常保存在一些有限的LRU池中,因此常用語句重用PreparedStatement實例。

這個難題的最後一部分是JDBC驅動程序可能自己決定要聰明並做到這一點;而且服務器本身也可能決定變得聰明,並檢測到提交與前一個結構類似的語句的客戶。

鑑於Hibernate本身並沒有保留PreparedStatement實例的緩存,所以你需要讓c3p0做到這一點,以獲得它們的好處。 (由於重複使用緩存計劃,這應該減少常見語句的開銷)。如果c3p0沒有緩存準備好的語句,那麼驅動程序只會看到應用程序準備一個語句,執行它,然後再次關閉它。看起來JDBC驅動程序有一個"threshold" setting用於在應用程序始終執行此操作的情況下避免準備/執行服務器開銷。所以,是的,你需要有c3p0做語句緩存。

希望有幫助,對不起有點冗長。答案是

+1

偉大的答案!有了你的詳細解釋,我可以進行一些測試。事實上:激活c3p0語句池是合理的。 之前,我的語句每次解析和計劃,現在他們只能綁定和執行。 但請注意您的數據是否改變以及舊計劃的執行效果不佳。我還不知道postgresql是否會不時重複準備好的語句。 非常感謝你的幫助! – Janning 2010-05-28 19:50:23

+0

很棒的回答!實際上,我總是對PreparedStatement的實現感到困惑,並且懷疑每個人都告訴我的好處。 – Chao 2016-07-31 18:06:16

2

記住語句具有每連接被緩存,這將意味着你將要消耗的內存相當一大塊,而且需要很長一段時間之前,你會看到任何好處。因此,如果您將它設置爲使用100條語句進行緩存,那實際上是100 *個連接數或100個/否連接,但您仍然需要花費相當長的時間,直到您的緩存具有任何有意義的效果。