首页 > 解决方案 > JDBC PostgreSQL 插入性能

问题描述

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

问题如下:

将 JSON 数组解析为 SQL 插入语句,解析为通过外键连接的两个表,所有这些都在一个事务中,一旦出错,只有错误的条目被回滚(这样连接的表中就没有孤儿数据)。

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

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

现在,这工作得相当好,直到有数万或数十万条记录要插入。前几千个非常顺利,每秒插入 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/sec 开始,那么代码、网络和数据库服务器至少能够支持这一点。

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

标签: sqlpostgresqljdbcinsertbulkinsert

解决方案


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

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

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


推荐阅读