许多列和数据的大小可能会有所不同.在一个示例项目中,我有一张约有170列.有一个唯一的索引 – 即使在删除索引后,插入的速度也没有改变.
我正在使用JDBC驱动程序连接到数据库,并且我以250行的批量插入数据(使用NamedParameterJdbcTemplate).
我花了大约18秒在Postgres上插入数据. MysqL上相同的数据集只需一秒钟.这是一个巨大的区别 – 它来自哪里? Postgres的JDBC驱动程序慢吗?可以用某种方式配置来使其更快吗?我还想念别的吗Postgres和MysqL之间的区别是如此巨大.任何其他想法如何使其更快?
我做了一个可以在Github – https://github.com/varad/postgresql-vs-mysql上提供的示例项目.一切都发生在LetsGo class的“运行”方法中.
解决方法
每次调用setValue()时,Spring都会尝试确定列的数据类型.它通过调用PreparedStatementMetaData.getParameterMetaData()
这显然会导致一个“准备”语句被发送到数据库本身,它本身是非常快的(从不超过我的笔记本电脑上的1ms),但是它被称为每行的每一列这总结了很多时间(它是呼叫每个非空值,导致约23.000个呼叫)
在某种程度上这更是一个Spring bug,那么一个驱动程序的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初始化之前设置该属性.
当我使用您的示例项目执行此操作时,插入在笔记本电脑上运行500ms.
编辑
在看到关于使用Postgres-NG驱动程序的意见之后,我将其打入“官方”驱动程序和NG驱动程序的源代码,而NG驱动程序在第一次调用后会缓存参数元数据,而官方驱动程序不会解释了为什么使用NG驱动程序要快得多(没有在Spring中禁用调用)