Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-68235

QSqlDatabase + PostgreSQL Batch Operations

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Incomplete
    • Icon: P3: Somewhat important P3: Somewhat important
    • None
    • 5.10.1
    • SQL Support
    • None

      Hello,

      I am experiencing extremely slow insert using Postgres. My app can only process about 1000 inserts every 17ish seconds.

      It seems that the QPSQL driver does not support batch executions even though the underlying libpq driver does. 

      This thread on StackOverflow makes two suggestions:

      https://stackoverflow.com/questions/7782842/fast-batch-executions-in-postgresql

      1. Prepare Query > Start Transaction > Exec in Loop > Commit
      2. Work around the driver limitation by using Postgres's unnest function.
        1. Doesn't work as you cannot call bindValue with a QVariantList and have it automatically convert to a Postgres array literal.

       My apps insertion code:

      (Performance is EXACTLY identical to using query.batchExec())

      void APPSQLWriter::crxtWriteQuotes(const QVarLengthArray<AppQuote> &quotes)
      {
          this->setIsBusy(true);
          this->m_writeElapsedTimer.restart();
      
          qInfo() << this << "Write Start: Length" << quotes.length();
      
          QSqlDatabase dbConnection = QSqlDatabase::database(this->m_connectionName);
          if (dbConnection.isOpen() == false || dbConnection.isValid() == false)
          {
              qWarning() << "APPSQLWriter: Write failed on bad connection";
              Q_ASSERT(false);
              emit this->error();
              return;
          }
      
          // Start a transaction
          Q_ASSERT(dbConnection.transaction() == true);
      
          QSqlQuery query(dbConnection);
      
          static const QString statement = QStringLiteral("SELECT app.append_quote(?, ?, ?, ?, ?, ?, ?, ?, ?);");
      
          bool prepared = query.prepare(statement);
          Q_ASSERT(prepared == true);
      
          for (const AppQuote &cQuote : quotes)
          {
              query.bindValue(0, cQuote.symbol());
              query.bindValue(1, cQuote.condition());
              query.bindValue(2, cQuote.bidExchangeId());
              query.bindValue(3, cQuote.askExchangeId());
              query.bindValue(4, cQuote.bidPrice());
              query.bindValue(5, cQuote.askPrice());
              query.bindValue(6, cQuote.bidSize());
              query.bindValue(7, cQuote.askSize());
              query.bindValue(8, cQuote.timeStampMs());
      
              if (query.exec() == false)
              {
                  qDebug() << "Failed to exec";
                  Q_ASSERT(false);
              }
          }
      
          // End Transaction
          Q_ASSERT(dbConnection.commit() == true);
      
          this->m_writeDurationMs = this->m_writeElapsedTimer.restart();
          qDebug() << this << "Finished" << this->m_writeDurationMs;
      
          this->setIsBusy(false);
      }
      

      Postgres and libpq both support Batch operations along with another form of mass insertion called the COPY command:

      DOCS1: https://www.postgresql.org/docs/current/static/sql-copy.html

      DOCS2: https://www.postgresql.org/docs/current/static/libpq-copy.html

      Example: https://www.safaribooksonline.com/library/view/practical-postgresql/9781449309770/ch04s03.html

      Batch operations for Postgres should be available since the underlying driver supports them.

      Implementation of the COPY command, though very database specific, would be even better.

       

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            andysh Andy Shaw
            think7 Andrew Ialacci
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved:

                There are no open Gerrit changes