所以,你的問題最後歸結爲「如何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有PREPARE
和DEALLOCATE
命令通過電線發送EXEC
時引用的聲明。它優化了兩件事情:
- 當使用
PREPARE
d聲明(換句話說,服務器準備的一個),客戶不必一次又一次地發送查詢文本。它只是發送一個簡短的查詢名稱和綁定變量的值。
- 從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驅動程序,或者您可以將所有查詢包裝到存儲過程中。 調用過程將在每次執行時重新進行調用,但是調用本身通常比組成過程的查詢短得多。
感謝您的回答,我看到您在9.4上一直在致力於此功能。所以,這意味着即使PreparedStatement被關閉,準備好的語句也可用於當前連接。這是一個好消息,因爲它允許重複使用對頻繁執行的語句進行解析/編譯。 –
還有一點需要注意:從9.2開始,PostgreSQL不會用PREPARE調用創建執行計劃 - 實際的計劃只能在EXECUTE時間完成(明確地從@VladMihalcea給出的文檔中引用,這意味着:所有緩存僅僅是緩存重寫的查詢 - 而不是執行計劃 –
感謝提示,它是緩存的解析,重寫和編譯,相關的執行計劃被延遲到執行時間 –