使用JDBC在PostgreSQL上缓慢插入

时间:2016-06-21 10:34:24

标签: java postgresql jdbc

我在一个将数据从云系统下载到本地数据库(PostgreSQL,MySQL,...)的系统上工作。现在我遇到了PostgreSQL性能问题,因为插入数据需要花费大量时间。

许多列和数据大小可能会有所不同。在一个示例项目中,我有一张大约一张桌子。 170列。有一个唯一索引 - 但即使在删除索引后,插入的速度也没有改变。

我使用JDBC驱动程序连接到数据库,并且我以250行的批量插入数据(使用NamedParameterJdbcTemplate)。

我花了大概。 18秒在Postgres上插入数据。 MySQL上的相同数据集只花了我一秒。这是一个巨大的差异 - 它来自哪里? Postgres JDBC驱动程序是慢的吗?是否可以以某种方式配置以使其更快?我错过了别的什么吗? Postgres和MySQL之间的区别是如此巨大。任何其他想法如何让它更快?

我制作了一个可在Github上使用的示例项目 - https://github.com/varad/postgresql-vs-mysql。一切都发生在"运行" LetsGo class中。方法

3 个答案:

答案 0 :(得分:12)

这似乎是一个Spring" bug"和一个司机" bug"。

Spring每次调用setValue()时都会尝试确定列的数据类型。它通过调用PreparedStatementMetaData.getParameterMetaData()

来完成此操作

这显然导致"准备"要发送到数据库的语句本身非常快(我的笔记本电脑上的时间不超过1毫秒),但每个行的每个都会调用它,这总计很多时间(它& #39; s为每个非空值调用,导致大约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中禁用调用)

答案 1 :(得分:2)

尝试使用pgjdbc-ng驱动程序,然后比较结果。

可在此处获取: http://impossibl.github.io/pgjdbc-ng/

答案 2 :(得分:-2)

我希望您使用的是DB Connection Pool。你可以试试C3P0。 Spring(JDBCTemplate)不提供连接池实现。