【问题标题】:Tips on Speeding up JDBC writes?加快 JDBC 写入速度的技巧?
【发布时间】:2010-09-26 23:49:21
【问题描述】:

我正在编写一个对 Postgres 数据库进行大量写入的程序。在一个典型的场景中,我会将 100,000 行写入一个规范化的表(三个外整数键,它们的组合是主键和表的索引)。我正在使用 PreparedStatements 和 executeBatch(),但是当我们要替换的嵌入式数据库(具有相同的外键约束和索引)在我的笔记本电脑上执行时,我只能设法在大约 70 秒内推入 10 万行10.

我是 JDBC 的新手,我不希望它能够击败自定义嵌入式数据库,但我希望它只慢 2-3 倍,而不是 7 倍。有什么明显我可能遗漏的东西吗?写入的顺序重要吗? (即说如果它不是索引的顺序?)。为了加快速度,需要注意什么?

【问题讨论】:

  • 更新:我应该补充一点,上述所有更新都是在一个事务中完成的,并且我尝试删除索引,没有太大影响(可能最多提高 20%,w/ o 计算重新添加的索引)。
  • 您要替换的嵌入式数据库是什么?

标签: java performance postgresql jdbc


【解决方案1】:

这是我在当前项目中经常不得不处理的一个问题。对于我们的应用程序,插入速度是一个关键瓶颈。但是,我们发现对于绝大多数数据库用户来说,选择速度是他们的主要瓶颈,因此您会发现有更多的资源来处理这个问题。

以下是我们提出的一些解决方案:

首先,所有解决方案都涉及使用 postgres COPY command。使用 COPY 将数据导入 postgres 是迄今为止最快的方法。但是,默认情况下,JDBC 驱动程序当前不支持通过网络套接字进行 COPY。因此,如果您想使用它,您需要执行以下两种解决方法之一:

  1. 修补以支持 COPY 的 JDBC 驱动程序,例如 one
  2. 如果您插入的数据和数据库在同一台物理机上,您可以将数据写入文件系统上的一个文件,然后使用 COPY 命令批量导入数据。

其他提高速度的选项是使用 JNI 来访问 postgres api,这样您就可以通过 unix 套接字进行对话,删除索引和 pg_bulkload project。但是,最终如果您不实施 COPY,您总是会发现性能令人失望。

【讨论】:

  • 感谢您的提示; “使用 JNI”是指使用 JNI 访问 COPY 还是发出常规 SQL 命令?也就是说,对于相同数量的 INSERT,您是否希望 JNI->C->SQL 比 JDBC 更快?
  • 我没有在postgres中对它进行基准测试,但我相信它是oracle驱动所采取的策略。通过 tcp 与 unix 套接字相比,存在性能开销。所以最后,为性能而定制的解决方案可能不值得付出努力,所以我将其视为最后的手段。
【解决方案2】:

检查您的连接是否设置为自动提交。如果 autoCommit 为 true,那么如果您在调用 executeBatch 时批处理中有 100 个项目,它将发出 100 个单独的提交。这可能比调用 executionBatch() 后跟一个显式的 commit() 慢很多。

我会避免在插入期间删除索引或外键的诱惑。它在负载运行时将表置于不可用状态,因为在索引消失时没有人可以查询表。另外,这似乎是无害的,但是当您尝试重新启用约束并且由于发生了您不希望发生的事情而失败时,您会怎么做? RDBMS 有完整性约束是有原因的,即使“暂时”禁用它们也是危险的。

【讨论】:

    【解决方案3】:

    您显然可以尝试更改批次的大小以找到最适合您的配置的大小,但我怀疑您会获得 3 倍。

    您也可以尝试调整您的数据库结构。使用单个字段作为主键时,您可能会比使用组合 PK 获得更好的性能。根据您需要的完整性级别,您可以通过停用数据库上的完整性检查来节省相当多的时间。

    您还可以更改正在使用的数据库。 MySQL 应该非常适合高速简单插入......而且我知道有一个 MySQL 分支试图削减功能以在高并发访问时获得非常高的性能。

    祝你好运!

    【讨论】:

      【解决方案4】:

      尝试禁用索引,并在插入后重新启用它们。另外,将整个过程包装在一个事务中

      【讨论】:

        最近更新 更多