3

要在 PostgreSQL 中插入批量数据/填充数据库,最快的方法是使用 COPY。来源
我必须填充一个数据库。现在,我的写入速度低至每秒 100-200 次。这涉及通过 C++ 库libpqxx发送许多单独的 INSERTS 。我认为的两个原因是:

  1. 数据有很多重复记录。(我有原始日志,我对其进行解析和发送。)这会导致主键异常。
  2. 插入语句的一一发送。

第一个不在我手中。但是我正在阅读第二个。
据我所知,tablewriter 类适合这个目的。然而,它显然已被弃用。我已经读过可以使用 stdin 作为参数进行复制。
但在这些线索之后,我迷路了。有人可以引导我找到解决方案吗?

编辑:这是代码,我有一个执行statemnt的函数:

void pushLog(Log log,pqxx::connection *conn){
    pqxx::work w(*conn);
    std::stringstream stmt;
    stmt<<"INSERT INTO logs VALUES('"<<log.getDevice()<<"','"<<log.getUser()<<"','"<<log.getDate()<<"','"<<log.getLabel()<<"');";
    try{
        pqxx::result res = w.exec(stmt.str());
        w.commit();
    }
    catch(const std::exception &e){
        std::cerr << e.what() << std::endl;
        std::cout<<"Exception on statement:["<<stmt.str()<<"]\n";
        return;
    }

}

我较早地建立了连接,并传递了对它的引用。

PS:这个问题可能缺少一些细节。如果是这样,请发表评论,我将编辑并添加它们。

4

1 回答 1

1

pushLog函数分别提交每个插入,并且提交很慢。

如文档的填充数据库中所述:

如果您允许单独提交每个插入,PostgreSQL 会为添加的每一行做很多工作

还:

在一个事务中进行所有插入的另一个好处是,如果插入一行失败,那么插入到该点的所有行的插入都将回滚,因此您不会被部分加载的数据卡住

但是,在您的情况下,这将是一个问题而不是好处,因为每个 INSERT 都可能因违反主键而失败,从而取消自上次提交以来的先前 INSERT。请注意COPY,如果您使用它,这也将是一个问题。

由于确实有必要在事务中对查询进行分组以提高性能,因此您需要以不中止事务的方式处理主键违规。

通常使用两种方法:

  1. 避免错误:INSERT INTO... WHERE NOT EXISTS (SELECT 1 FROM table WHERE primary_key=...)

  2. 通过在具有忽略 itr 的 EXCEPTION 块的 plpgsql 函数中插入来捕获错误。导致重复的特定 INSERT(s) 将被取消,但事务不会中止。

如果您有并发插入,则需要使用锁定策略来改进这些方法。

于 2013-10-30T18:19:44.720 回答