C ++,Postgres,libpqxx巨大的查询

时间:2014-04-28 05:16:50

标签: c++ postgresql libpqxx

我必须通过以下代码对Postgres执行SQL查询。查询返回大量行(40M或更多),并有4个整数字段:当我使用32Gb的工作站时,一切正常,但在16Gb工作站上,查询非常慢(由于交换,我猜)。有没有办法告诉C ++批量加载行,而不是等待整个数据集?使用Java我之前从未遇到过这些问题,因为可能有更好的JDBC驱动程序。

try {
        work W(*Conn);
        result r = W.exec(sql[sqlLoad]);
        W.commit();

        for (int rownum = 0; rownum < r.size(); ++rownum) {
            const result::tuple row = r[rownum];
            vid1 = row[0].as<int>();
            vid2 = row[1].as<int>();
            vid3 = row[2].as<int>();
            ..... 

    } catch (const std::exception &e) {
        std::cerr << e.what() << std::endl;
    }

我正在使用PostgreSQL 9.3,在那里我看到了http://www.postgresql.org/docs/9.3/static/libpq-single-row-mode.html,但我不知道如何在我的C ++代码中使用它。我们将非常感谢您的帮助。

编辑:此查询仅运行一次,用于创建必要的主内存数据结构。因此,tt无法优化。此外,pgAdminIII可以在相同(或较小的RAM)PC下一分钟内轻松获取这些行。此外,Java可以轻松处理两倍的行数(使用Statent.setFetchSize()http://docs.oracle.com/javase/7/docs/api/java/sql/Statement.html#setFetchSize%28int%29)因此,它实际上是libpqxx库的问题,而不是应用程序问题。有没有办法在C ++中强制执行此功能,而无需手动明确设置限制/偏移?

3 个答案:

答案 0 :(得分:2)

使用cursor

另见FETCHcursor将在幕后使用它,我收集,但为了以防万一,您始终可以使用FETCH手动编码流检索。

答案 1 :(得分:1)

为了回答我自己的问题,我改编了How to use pqxx::stateless_cursor class from libpqxx?

try {
        work W(*Conn);
        pqxx::stateless_cursor<pqxx::cursor_base::read_only, pqxx::cursor_base::owned>
                cursor(W, sql[sqlLoad], "mycursor", false);
        /* Assume you know total number of records returned */
        for (size_t idx = 0; idx < countRecords; idx += 100000) {
            /* Fetch 100,000 records at a time */
            result r = cursor.retrieve(idx, idx + 100000);
            for (int rownum = 0; rownum < r.size(); ++rownum) {
                const result::tuple row = r[rownum];
                vid1 = row[0].as<int>();
                vid2 = row[1].as<int>();
                vid3 = row[2].as<int>();
                .............
            }
        }
    } catch (const std::exception &e) {
        std::cerr << e.what() << std::endl;
    }

答案 2 :(得分:0)

光标是一个很好的起点。这是另一个光标示例,使用do-while()

     const std::conStr("user=" + opt::dbUser + " password=" + opt::dbPasswd + " host=" + opt::dbHost + " dbname=" + opt::dbName);                                            

      pqxx::connection conn(connStr);
      pqxx::work txn(conn);
      std::string selectString = "SELECT id, name FROM table_name WHERE condition";

      pqxx::stateless_cursor<pqxx::cursor_base::read_only, pqxx::cursor_base::owned> 
      cursor(txn, selectString, "myCursor", false);

      //cursor variables
      size_t idx = 0;       //starting location
      size_t step = 10000;  //number of rows for each chunk
      pqxx::result result;
      do{
        //get next cursor chunk and update the index
        result = cursor.retrieve( idx, idx + step );
        idx += step;

        size_t records = result.size();
        cout << idx << ": records pulled = " << records << endl;

        for( pqxx::result::const_iterator row : result ){
          //iterate over cursor rows
        }
      }
      while( result.size() == step ); //if the result.size() != step, we're on our last loop
      cout << "Done!" << endl;

我在应用程序中迭代了大约3300万行。除了使用游标之外,我还使用以下方法:

  1. 将数据拆分为较小的块。对我来说,那是使用边界 框以获取给定区域中的数据。
  2. 构造查询以获取 块,并使用游标对其进行迭代。
  3. 将块存储在 处理完给定数据后,将其堆积并释放它们 块。

我知道这是您问题的很晚答案,但是我希望这可以对某人有所帮助!