我正在编写一个对Postgres数据库进行大量写操作的程序。在一个典型的场景中,我会写出100,000行表示规范化(三个外部整数键,其组合是主键和表的索引)。我正在使用PreparedStatements和executeBatch(),但我只能设法在我的笔记本电脑上大约70秒内推出100k行,当我们要替换的嵌入式数据库(具有相同的外键约束和索引)时10。
我是JDBC的新手,我不希望它超过自定义嵌入式数据库,但我希望它只慢2-3倍,而不是7倍。有什么明显的我可能会错过吗?写作的顺序是否重要? (即如果它不是索引的顺序?)。需要注意的是要挤出更快的速度?
答案 0 :(得分:8)
这是我在当前项目中不得不经常处理的问题。对于我们的应用,插入速度是一个关键的瓶颈。但是,我们已经发现绝大多数数据库用户都将选择速度作为主要瓶颈,因此您会发现有更多资源可以解决该问题。
以下是我们提出的一些解决方案:
首先,所有解决方案都涉及使用postgres COPY command。使用COPY将数据导入postgres是迄今为止最快的方法。但是,默认情况下,JDBC驱动程序当前不支持网络套接字上的COPY。因此,如果您想使用它,则需要执行以下两种解决方法之一:
提高速度的其他选项是使用JNI来命中postgres api,这样你就可以通过unix套接字进行通信,删除索引和pg_bulkload project。但是,如果你没有实施COPY,你最终会发现性能令人失望。
答案 1 :(得分:3)
检查您的连接是否设置为autoCommit。如果autoCommit为true,那么如果在调用executeBatch时批处理中有100个项目,它将发出100个单独的提交。这可能比调用executionBatch()后跟一个显式commit()慢很多。
我会避免在插入过程中丢弃索引或外键的诱惑。它会在负载运行时将表置于不可用状态,因为在索引消失时没有人可以查询表。此外,它似乎无害,但是当你尝试重新启用约束时它会怎么做而它失败了,因为你没想到会发生什么事情?由于某种原因,RDBMS具有完整性约束,即使“暂时”禁用它们也是危险的。
答案 2 :(得分:1)
您显然可以尝试更改批量的大小以找到最适合您配置的大小,但我怀疑您是否会获得3倍。
您还可以尝试调整数据库结构。使用单个字段作为主键比使用组合PK时可能有更好的性能。根据您所需的完整性级别,您可以通过停用数据库上的完整性检查来节省相当长的时间。
您也可以更改正在使用的数据库。 MySQL应该对高速简单插入非常有用......而且我知道有一个MySQL的分支试图削减功能以在高度并发访问上获得非常高的性能。
祝你好运!答案 3 :(得分:1)
尝试禁用索引,并在插入后重新启用它们。另外,将整个过程包装在一个事务中