我正在编写一个.NET 4应用程序,它将大量数据从文件导入PostgreSQL 9.1数据库。分析表明实际插入数据的DB调用占用了90%以上的时间。数据库服务器似乎是CPU限制的 - 使用所有一个CPU。
如果可能的话,我想通过使用所有CPU来更快地导入数据。输入文件可以在客户端上分解成碎片,所以这通常不会太难,但我想确保如果在导入文件时发生任何错误,那么DB根本不会被修改。为了实现这一点,我在一次交易中进行整个导入。
是否有可能以某种方式将并发命令发送到数据库服务器(以利用其所有CPU),但是仍然确保整个导入成功或没有进行任何更改?据我所知,一个事务不能从多个线程同时运行多个命令,可以吗?我正在使用Npgsql作为ADO.NET提供程序,如果这有所不同。
答案 0 :(得分:4)
在 Postgres 9.6 之前,使用标准PostgreSQL的多个线程无法并行处理事务,此功能已添加为"parallel query"。
但是,您的INSERT操作受CPU限制似乎很可疑。这里可能会改进一些事情。您如何将数据发送到服务器?基本上有四种方法将INSERT
数据放入表中:
VALUES
表达式提供文字VALUES
表达式INSERT
SELECT
(插入0-n行)COPY
COPY
是迄今为止最快的方法。
在庞大的批量INSERT
/ COPY
之前删除索引会更快,然后重新创建它们。增量添加索引元组的效率远低于一次创建索引的效率。
触发器,约束或外键约束是可能会降低您速度的其他因素。也许您可以在批量加载之前禁用/删除并在之后启用/重新创建?
还有许多设置可以产生重大影响。
您可以关闭fsync and synchronous_commit。 (危险!)
暂时停用autovacuum
。之后立即运行ANALYZE
。 (小心那些!)
阅读Postgres Wiki中有关Bulk Loading and Restores和Tuning Your PostgreSQL Server的文章,尤其是 checkpoint_segments 和 checkpoint_completion_target 上的段落。
操作可能不像看起来那样受CPU限制。看看这个paragraph in the PostgreSQL Wiki。
另一个减速源可能是伐木。例如,log_statement = all
会产生巨大的日志文件,但代价是单行插入。
这是PostgreSQL Wiki中的quick method to check all your custom settings。
另一个加快速度的想法,特别是当你无法关闭fsync时。创建一个或多个空临时表,如下所示:
CREATE TEMP TABLE x_tmp AS SELECT * FROM real_tbl LIMIT 0;
考虑如何处理序列和其他默认值!
INSERT
将所有数据导入登台表,然后在一个命令中写入目标表。索引和约束再次关闭,但时间要短得多。
INSERT INTO real_tbl SELECT * FROM x_tmp ORDER BY something;
DROP TABLE x_tmp;
可能会快得多。务必使用足够的RAM进行各种设置。特别要注意temp_buffers
。
答案 1 :(得分:0)
另一个行动计划可能是:
在这种情况下,您支付更多的IO硬币可以减轻您当前的瓶颈(由于输入处理而受到CPU限制)。
答案 2 :(得分:0)
我会说你应该使用prepared transactions。根据需要并行运行多个,如果它们都进入舞台,它们可以毫无错误地准备好,然后提交准备它们,否则回滚准备它们。
首先必须将max_prepared_transactions设置为大于0的某个值并重新启动postgresql。之后,您可以在单个会话中启动事务,如下所示:
begin;
select yada;
insert yada;
update yada;
prepare transaction 'mytrans';
此时您将收到通知“PREPARE TRANSACTION”或“ROLLBACK”。如果您从任何准备好的事务中获得ROLLBACK,那么您可以对每个事务进行回滚准备,而不进行任何事务。请注意,您不应该留下大量准备好的交易。
答案 3 :(得分:0)
请注意,pg_restore现在使用多线程模式在恢复压缩转储时从多核架构中获益。所以在几个联系上管理大量进口当然是个好主意。我已经看到了将作业数量设置为2 *核心pg_restore的好收益报告。
但是pg_restore不能在此设置中使用--single-transaction
。所以和你一样的问题。您可以使用PREPARE TRANSACTION语句尝试两阶段提交事务,它通常由事务管理器完成,而不是应用程序,但如果其中一个事务导入失败,这可能会帮助您使多个事务无效过程