【问题标题】:JDBC PostgreSQL Insert PerformanceJDBC PostgreSQL 插入性能
【发布时间】:2018-05-25 06:58:56
【问题描述】:

在前几千次插入后,我的 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 开始,那么代码、网络和数据库服务器至少能够支持这一点。

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

【问题讨论】:

  • 我猜 FK 正在减慢速度(检查值是否存在)。 1)你在 FK 列上有索引吗? 2)您是否考虑过删除 FK 并在加载后重新创建它或使其延迟?
  • 外键不能使插入逐渐变慢。我会检查 I/O 问题。如果 I/O 是问题,增加 max_wal_sizecheckpoint_completion_target 可能会有所帮助。您可以使用auto_explain 来获取EXPLAIN (ANALYZE, BUFFERS) 的输出,用于快速和慢速查询,也许您可​​以发现问题。这些是简单的插入吗?如果没有,也许定期 ANALYZE 可以提供帮助。
  • 删除所有外键会按比例提高速度,但它从每秒插入 500 次开始,到插入 30.000 条记录时减慢到 150 次。
  • 我尝试使用 max_wal_size 并将 checkpoint_completion_target 设置为 0.9,但它并没有改变太多。每秒 50 个对象,即 100 个插入(一个用于父表,一个用于子表),因此单个查询执行时间为 10 毫秒,这不是我想象的慢查询

标签: sql postgresql jdbc insert bulkinsert


【解决方案1】:

即使你“释放一个保存点”,数据库keeps memory structures till the end of a transaction。你真的提交了行吗?

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

如果上述方法没有帮助,那么继续分析数据库进程(例如通过perf),看看是什么导致了瓶颈。

【讨论】:

    猜你喜欢
    • 2011-02-28
    • 2013-05-05
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    • 1970-01-01
    • 2012-08-25
    相关资源
    最近更新 更多