JDBC PostgreSQL 插入性能



在最初的几千次插入之后,我在PostgreSQL数据库中的插入速率逐渐变慢,我无法找到为什么会发生这种情况的解释。也许有人可以帮助解释这一点:

问题如下:

将 JSON 数组解析为 SQL 插入语句,解析为由外键连接的两个表,所有这些都在单个事务中,在出错时,只会回滚错误的条目(以便连接的表中没有孤立数据(。

稍微需要注意的是,这些 INSERT 应该是通用的(构建一个用于将用户提供的数据动态加载到系统中的工具(。

所以我的解决方案是在文件的开头开始事务,并为每个条目创建一个保存点。如果该条目有错误,事务将回滚到该保存点(并释放保存点(,如果没有错误,则释放保存点并继续导入。

现在,这工作得相当好,直到有数万或数十万条记录要插入。最初的几千个非常顺利,每秒插入300-400个,但随后开始逐渐减慢。

Done 200, rate 200/s, succeeded 200 failed 0
Done 300, rate 300/s, succeeded 300 failed 0
Done 400, rate 400/s, succeeded 400 failed 0
Done 500, rate 250/s, succeeded 500 failed 0
Done 600, rate 300/s, succeeded 599 failed 1
Done 700, rate 233/s, succeeded 699 failed 1
Done 800, rate 266/s, succeeded 799 failed 1
Done 900, rate 300/s, succeeded 899 failed 1
Done 1000, rate 250/s, succeeded 999 failed 1
Done 1100, rate 275/s, succeeded 1099 failed 1
...
Done 5200, rate 185/s, succeeded 5195 failed 5
Done 5300, rate 182/s, succeeded 5295 failed 5
Done 5400, rate 186/s, succeeded 5395 failed 5
Done 5500, rate 183/s, succeeded 5495 failed 5
...
Done 31000, rate 58/s, succeeded 30953 failed 47
Done 31100, rate 58/s, succeeded 31053 failed 47
Done 31200, rate 57/s, succeeded 31153 failed 47

因此,在 30.000 次插入后,它的速度已经减慢到只有开始时的 1/5。 这些表是非常简单的表,具有几个 VARCHAR、几个数字、一个主键和一个外键。没有函数,触发器或其他任何东西。

我想知道JDBC中是否有某些东西保留了不再需要的资源,这可能会导致问题。当然,如果它以 300/秒开头,那么代码、网络和数据库服务器至少能够支持这一点。

我知道批处理会大大改善它,但对于我在这里描述的用例,它不起作用。

即使您"释放保存点",数据库也会保留内存结构,直到事务结束。你真的提交行吗?

  1. 您可能希望使用批处理 API,并在批处理语句之前使用保存点。例如:使用批次 100,如果失败,您可以逐个重试。或者重试一批 50 个。这启用了批处理API,减少了所需的保存点数量,允许跳过无效行等。
  2. 您可能希望不时提交事务,以避免后端的高内存消耗。

如果上述方法没有帮助,请继续分析数据库进程(例如通过perf(,以查看导致瓶颈的原因。

最新更新