[英]Slow insert on PostgreSQL using JDBC
我在一個系統上工作,該系統將數據從雲系統下載到本地數據庫(PostgreSQL,MySQL,...)。 現在我遇到了PostgreSQL性能問題,因為插入數據需要花費大量時間。
許多列和數據的大小可能會有所不同。 在一個示例項目中,我有一張大約一張桌子。 170列。 有一個唯一索引 - 但即使在刪除索引后,插入的速度也沒有改變。
我正在使用JDBC驅動程序連接到數據庫,我正在以250行的批量插入數據(使用NamedParameterJdbcTemplate )。
我花了大概。 在Postgres上插入數據需要18秒 。 MySQL上的相同數據集只花了我一秒鍾 。 這是一個巨大的差異 - 它來自哪里? Postgres JDBC驅動程序是慢的嗎? 是否可以以某種方式配置以使其更快? 我錯過了別的什么嗎? Postgres和MySQL之間的區別是如此巨大。 任何其他想法如何讓它更快?
我做了一個示例項目,可以在Github上找到 - https://github.com/varad/postgresql-vs-mysql 。 一切都發生在LetsGo類的“run”方法中。
看來這是Spring“bug”和驅動程序“bug”的組合。
每次調用setValue()
時,Spring都會嘗試確定列的數據類型。 它通過調用PreparedStatementMetaData.getParameterMetaData()
做到這一點
這顯然會導致一個“准備”語句被發送到數據庫本身非常快(我的筆記本電腦上的時間不超過1毫秒)但是因為每個列的每列調用它總共需要很多時間(這是調用每個非null值,導致大約23.000次調用)
在某種程度上,這更像是一個Spring bug然后是一個驅動程序錯誤,因為沒有緩存參數元數據並不真正有意義(至少在我看來)。 MySQL JDBC驅動程序不支持getParameterMetaData()
,Spring知道這一點,所以這個“bug”沒有出現在MySQL中,因為spring從不調用該方法。
我不確定Postgres的JDBC驅動程序行為是否可歸類為錯誤,但如果驅動程序在第一次調用后緩存該元數據,那肯定會很好。
Spring可以說服不通過屬性spring.jdbc.getParameterType.ignore
獲取語句元數據
所以通過:
System.setProperty("spring.jdbc.getParameterType.ignore", "true");
在行之前 :
LetsGo letsGo = new LetsGo();
此行為已禁用。
必須在 Spring初始化之前設置該屬性。
當我對您的示例項目執行此操作時,插入在我的筆記本電腦上運行500毫秒。
編輯
在看到有關使用Postgres-NG驅動程序的評論之后,我挖掘了“官方”驅動程序和NG驅動程序的來源,並且NG驅動程序在第一次調用后確實緩存了參數元數據,而官方驅動程序沒有解釋為什么使用NG驅動程序要快得多(不在Spring中禁用調用)
嘗試使用pgjdbc-ng驅動程序,然后比較您的結果。
它可以在這里找到: http : //impossibl.github.io/pgjdbc-ng/
我希望你使用的是DB Connection Pool。 你可以試試C3P0。 Spring(JDBCTemplate)不提供連接池實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.