同一事务中的并发数据库 (PostgreSQL) 命令

EMP*_*EMP 5 .net postgresql multithreading transactions thread-safety

我正在编写一个 .NET 4 应用程序,它将文件中的大量数据导入到 PostgreSQL 9.1 数据库中。分析显示,数据库调用实际 INSERT 数据占用了超过 90% 的时间。数据库服务器似乎受 CPU 限制 - 使用所有一个 CPU。

如果可能的话,我希望使用所有 CPU 更快地导入数据。输入文件可以在客户端上分成多个部分,因此这通常不会太难,但我想确保如果导入文件时发生任何错误,则数据库根本不会被修改。为了实现这一目标,我在一笔交易中完成了整个导入。

是否可以以某种方式向数据库服务器发送并发命令(以利用其所有 CPU),但仍确保整个导入成功或不进行任何更改?据我了解,不能从多个线程使用事务来同时运行多个命令,可以吗?我正在使用 Npgsql 作为 ADO.NET 提供程序,如果这有什么区别的话。

Erw*_*ter 4

在Postgres 9.6之前,标准 PostgreSQL 无法通过多个线程并行处理事务,该功能被添加为“并行查询”

不过,您的 INSERT 操作受 CPU 限制似乎很可疑。这里可能需要改进一些事情。具体如何将数据发送到服务器?基本上有四种将INSERT数据存入表的方法:

  1. 一次一行,带有VALUES提供文字的表达式
  2. VALUES一个表达式一次多行
  3. INSERTwith SELECT(插入 0-n 行)
  4. COPY

COPY是迄今为止最快的方法。

  • 在大量/之后删除索引并在之后重新创建它们会更快。增量添加索引元组的效率比一次创建索引低得多。INSERTCOPY

  • 触发器、约束或外键约束是可能减慢速度的其他因素。也许您可以在批量加载之前禁用/删除并在之后启用/重新创建?

还有许多设置可以产生重大影响。

  • 您可以关闭fsyncsynchronous_commit。(有风险!)

  • autovacuum暂时禁用。ANALYZE之后立即运行。(小心那些!)

阅读 Postgres Wiki 中有关批量加载和恢复以及调整 PostgreSQL 服务器的文章,尤其是有关checkpoint_segmentscheckpoint_completion_target的段落。

该操作可能并不像看起来那样受 CPU 限制。看看PostgreSQL Wiki 中的这一段

速度放缓的另一个原因可能是日志记录。例如,log_statement = all会产生巨大的日志文件,但需要付出一定的代价,尤其是在单行插入时。

这是再次检查 PostgreSQL Wiki 中所有自定义设置的快速方法。

另一个加快速度的想法,特别是当你无法关闭 fsync 时。创建一个或多个空临时表,如下所示:

CREATE TEMP TABLE x_tmp AS SELECT * FROM real_tbl LIMIT 0;
Run Code Online (Sandbox Code Playgroud)

思考一下如何处理序列和其他默认值! INSERT将所有数据写入暂存表,然后通过一个命令写入目标表。索引和约束再次关闭,但时间要短得多。

INSERT INTO real_tbl SELECT * FROM x_tmp ORDER BY something;
DROP TABLE x_tmp;
Run Code Online (Sandbox Code Playgroud)

可能会快得多。确保为各种设置使用足够的 RAM。temp_buffers特别看一下。