2015-08-30 18 views
7

按照PostgreSQL documentation的壽命,一份準備好的聲明綁定到一個數據庫會話/連接:什麼是PostgreSQL服務器端預處理語句

prepare創建一個準備好的聲明。準備好的語句是可以用來優化性能的服務器端對象 。執行 PREPARE語句時,會分析指定的語句,並分析並重寫 。當發出EXECUTE命令後, 已發佈,準備好的語句將被計劃並執行。

準備好的陳述僅在當前數據庫 會話期間持續。當會話結束時,準備好的語句被遺忘, 因此必須在重新使用之前重新創建。

但隨後,Markus Winand (author of SQL Performance Explained) says that

PostgreSQL沒有共享的查詢計劃緩存,但它對於準備語句的 可選的查詢計劃緩存。這意味着 開發人員可以選擇使用準備好的語句,無論有沒有 緩存的查詢計劃。但請注意,當準備好的語句關閉時,緩存將被丟棄。

哪一個是真的?

只要數據庫連接處於打開狀態,準備好的語句是否處於活動狀態,因此在使用連接池時,只要池沒有明確關閉物理連接或者服務器端預處理語句已被擦除一旦JDBC PreparedStatement關閉。

回答

13

所以,你的問題最後歸結爲「如何java.sql.PreparedStatement玩PostgreSQL」。最後,請參閱「如何與服務器準備的計劃搭配」的答案。

下面是答案:取決於您使用的JDBC驅動程序。

TL; DR:現代司機服務器準備的聲明中生活,直到連接死亡或直至語句由另一個(常規LRU逐出)驅逐。

注意:PostgreSQL服務器不能在數據庫連接之間共享預準備語句,因此最好的JDBC驅動程序可以做的是將計劃緩存在每個連接中。

注意:JDBC規範要求使用?, ?作爲綁定佔位符,而服務器要求$1, $2,因此JDBC驅動程序也緩存所謂的已分析SQL文本。

有兩個著名的JDBC驅動程序:pgjdbc和pgjdbc-ng的

pgjdbc

https://github.com/pgjdbc/pgjdbc

由於pgjdbc 9.4-1202它使用PreparedStatement時自動緩存服務器端的計劃。 注意:即使您的close()PreparedStatement,語句也會被緩存。 爲了進行服務器端準備,您需要執行5次查詢(可通過prepareThreshold進行配置)。

目前,緩存是按每個連接實現的。默認情況下,pgjdbc緩存256(preparedStatementCacheQueries)個查詢,最多可查詢preparedStatementCacheSizeMiB個查詢。這是一個保守的設置,所以你可能需要調整它。有關屬性的描述,請參閱documentation。 緩存包括解析的和服務器準備的語句。

GitHub的問題:https://github.com/pgjdbc/pgjdbc/pull/319

pgjdbc-ng的

https://github.com/impossibl/pgjdbc-ng

我沒有把pgjdbc-NG,但是看起來它確實既解析(默認緩存大小爲250查詢)服務器準備(默認緩存大小爲50查詢)。服務器端預處理語句的支持於2014年2月24日發佈,因此如果您使用的是最新版本,則可以獲得語句緩存。

注意:如果您意外地使用了很長的查詢,您可以點擊OutOfMemory,因爲pgjdbc-ng不能根據保留字節數驅逐條目。

緩存是按連接的,因此即使關閉語句,它也是透明使用的。

我不能說pgjdbc-ng的性能很多,但自從上次嘗試拋出jmh時,它隨機異常失敗。

GitHub的問題:https://github.com/impossibl/pgjdbc-ng/pull/69

服務器準備的計劃

PostgreSQL有PREPAREDEALLOCATE命令通過電線發送EXEC時引用的聲明。它優化了兩件事情:

  1. 當使用PREPARE d聲明(換句話說,服務器準備的一個),客戶不必一次又一次地發送查詢文本。它只是發送一個簡短的查詢名稱和綁定變量的值。
  2. 從9.2開始,數據庫仍然試圖重新規劃查詢的前幾個執行。它這樣做是爲了嘗試查詢是否需要多個計劃或通用計劃是否足夠好。最終(立即如果查詢沒有參數),數據庫might switch to a generic plan

換句話說,PreparedStatement優化了JDBC端的查詢解析和數據庫端的查詢計劃。

這裏更多的信息:在PL/pgSQL的

http://blog.endpoint.com/2014/04/custom-plans-prepared-statements-in.html

預處理語句按文檔,PostgreSQL的caches計劃在PL/pgSQL裏使用的查詢。這發生在幾次執行後(3或5,我不記得確切的閾值),所以在創建存儲過程之後它可能會有點慢,然而它會切換到緩存計劃(假設數據庫同意使用通用計劃對於特定的查詢)。

換句話說,爲了實現「緩存執行計劃」,您需要使用最新的JDBC驅動程序,或者您可以將所有查詢包裝到存儲過程中。 調用過程將在每次執行時重新進行調用,但是調用本身通常比組成過程的查詢短得多。

+0

感謝您的回答,我看到您在9.4上一直在致力於此功能。所以,這意味着即使PreparedStatement被關閉,準備好的語句也可用於當前連接。這是一個好消息,因爲它允許重複使用對頻繁執行的語句進行解析/編譯。 –

+0

還有一點需要注意:從9.2開始,PostgreSQL不會用PREPARE調用創建執行計劃 - 實際的計劃只能在EXECUTE時間完成(明確地從@VladMihalcea給出的文檔中引用,這意味着:所有緩存僅僅是緩存重寫的查詢 - 而不是執行計劃 –

+0

感謝提示,它是緩存的解析,重寫和編譯,相關的執行計劃被延遲到執行時間 –

3

我認爲兩者都是真實的,但有疑問PostgreSQL文檔通常比我更真實。但是,在這裏我認爲PostgreSQL文檔可能不準確。

它也許應該這樣寫:

預處理語句只有最後直到DEALLOCATE版,長度不超過當前數據庫會話的持續時間。

沒有檢查我會堅信當JDBC PreparedStatement關閉時,JDBC驅動程序會取消分配服務器端預處理語句。

+0

謝謝。我將不得不在PG郵件列表中添加這個問題。 –

+0

因爲大量的應用程序都是用'prepare-execute-close'方式編寫的,因此跨'close()'調用的'pgdjbc'和'pgjdbc-ng'緩存語句。 –