加速 Qt 中的 Oracle 数据库接口 (QOCI)

Bas*_*ond 5 c++ database oracle qt

我有一个项目涉及将 Oracle 数据库集成到 Qt 桌面应用程序中。由于 Qt 有一个非常易于使用的数据库交互界面,因此我编译了 QOCI 驱动程序来支持 Oracle 连接。

一切工作正常,但查询的处理时间非常慢。我怎样才能提高性能?

我处理任意查询的代码如下所示:

QList< QList<QString> > DBWrapper::executeQuery(QString const& queryString)
{
    QList< QList<QString> > results;
    if (_db.isOpen()) {
        QSqlQuery qry(queryString);
        if(qry.exec()) {
            while(qry.next()) {
                QList<QString> row;
                results.append(row);
                for(int i = 0; i < qry.record().count(); ++i) {
                    results.last().append(qry.value(i).toString());
                }
            }
        } else {
            qDebug() << queryString;
            qDebug() << "FAILURE: cannot handle query.";
            qDebug() << "  > " << qry.lastError();
        }
    } else {
        qDebug() << "Error Opening Database = " << _db.lastError();
    }

    return results;
}
Run Code Online (Sandbox Code Playgroud)

Bas*_*ond 4

有一些资源描述了 Qt 中其他 DBMS 的相同问题。他们所有人都建议添加qry.setForwardOnly(true)qry.prepare(queryString);添加到查询设置中。

虽然,这看起来是阅读 Qt 文档的良好风格,但它几乎没有给我带来任何改进。调试代码时我运行了一些速度测试,减少了所有内容,只是为了测量 QSql 内容的运行时间。

//...
QSqlQuery qry(queryString);
qry.setForwardOnly(true);
qry.prepare(queryString);

QElapsedTimer timer;
timer.start();
if(qry.exec()) {
    qDebug() << "time to execute query: " << timer.elapsed() << "ms";
    timer.start();
    while(qry.next()) {
         // don't do anything here
    }
    qDebug() << "time to iterate through query results: " << timer.elapsed() << "ms";
}
Run Code Online (Sandbox Code Playgroud)

事实证明,执行查询的时间不到 50 毫秒,而迭代结果大约花费了 3000 毫秒,SELECT 语句的结果中只有 100 个元素。

解决方案很难找到,但看起来相当简单。设置数据库连接时,您可以定义特定于您正在使用的 DBMS 类型的连接选项。OCI 定义OCI_ATTR_PREFETCH_ROWS,默认为 1。设置较高的值可快速提高迭代速度。

_db = QSqlDatabase::addDatabase("QOCI");
_db.setHostName(host);
_db.setDatabaseName(dbName);
_db.setPort(port);
_db.setUserName(user);
_db.setPassword(pwd);

_db.setConnectOptions("OCI_ATTR_PREFETCH_ROWS=1000");

_db.open();
Run Code Online (Sandbox Code Playgroud)

如果我错了,请有人纠正我,但我猜测每个选择查询都会在 Qt 的底层存储结构中缓存最大数量的行。我相信这个数字等于 的值OCI_ATTR_PREFETCH_ROWS。由于qry.value(...)仅指向一行(QSqlRecord),我假设这OCI_ATTR_PREFETCH_ROWS = 1意味着在每个qry.next()数据库上将以某种方式在内部再次查询以移动该游标。这会完全破坏性能,就像对我一样。

我希望像我一样面临这个问题的人能够找到这篇文章。

  • 只是本能,但我想说的是客户端和数据库服务器之间的所有往返都会影响您的性能 - 将每次行程获取的行数增加到 1000 听起来像是正确的选择。参见http://docs.oracle.com/cd/B28359_01/appdev.111/b28395/oci04sql.htm#i429698 (2认同)