我在一个将数据从云系统下载到本地数据库(PostgreSQL,MySQL,...)的系统上工作。现在我遇到了PostgreSQL性能问题,因为插入数据需要花费大量时间。
许多列和数据大小可能会有所不同。在一个示例项目中,我有一张大约一张桌子。 170列。有一个唯一索引 - 但即使在删除索引后,插入的速度也没有改变。
我使用JDBC驱动程序连接到数据库,并且我以250行的批量插入数据(使用NamedParameterJdbcTemplate)。
我花了大概。 18秒在Postgres上插入数据。 MySQL上的相同数据集只花了我一秒。这是一个巨大的差异 - 它来自哪里? Postgres JDBC驱动程序是慢的吗?是否可以以某种方式配置以使其更快?我错过了别的什么吗? Postgres和MySQL之间的区别是如此巨大。任何其他想法如何让它更快?
我制作了一个可在Github上使用的示例项目 - https://github.com/varad/postgresql-vs-mysql。一切都发生在"运行" LetsGo class中。方法
答案 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驱动程序,然后比较结果。
答案 2 :(得分:-2)
我希望您使用的是DB Connection Pool。你可以试试C3P0。 Spring(JDBCTemplate)不提供连接池实现。