使用JDBC在PostgreSQL上缓慢插入

var*_*rad 16 java postgresql 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"方法中.

a_h*_*ame 16

看来这是Spring"bug"和驱动程序"bug"的组合.

Spring每次setValue()调用时都会尝试确定列的数据类型.它通过调用来做到这一点PreparedStatementMetaData.getParameterMetaData()

这显然会导致一个"准备"语句被发送到数据库本身非常快(我的笔记本电脑上的时间不超过1毫秒)但是因为它为每一行的每调用,所以总计很多时间(这是调用每个非空值,导致大约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");
Run Code Online (Sandbox Code Playgroud)

在行之前:

LetsGo letsGo = new LetsGo();
Run Code Online (Sandbox Code Playgroud)

此行为已禁用.

必须 Spring初始化之前设置该属性.

当我对您的示例项目执行此操作时,插入在我的笔记本电脑上运行500毫秒.


编辑

在看到有关使用Postgres-NG驱动程序的评论之后,我挖掘了"官方"驱动程序和NG驱动程序的来源,并且NG驱动程序在第一次调用后确实缓存了参数元数据,而官方驱动程序没有解释为什么使用NG驱动程序要快得多(不在Spring中禁用调用)