14

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

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

4

4 回答 4

8

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

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

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

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

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

于 2008-12-16T00:19:25.843 回答
3

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

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

于 2008-12-16T02:01:09.943 回答
1

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

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

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

祝你好运 !

于 2008-12-15T16:05:18.693 回答
1

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

于 2008-12-15T16:16:31.323 回答