C ++,Postgres,libpqxx巨大查询

问题描述 投票:4回答:3

我必须通过以下代码对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 ++代码中使用它。您的帮助将不胜感激。

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

c++ postgresql libpqxx
3个回答
2
投票

使用cursor

另请参阅FETCH。我收集到,cursor将在后台为您使用,但以防万一,您始终可以使用FETCH手动编码流检索。


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;
    }

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. 将大块存储在处理完给定数据后,将其堆积并释放它们块。

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

© www.soinside.com 2019 - 2024. All rights reserved.