为什么我的 sqlite 查询在 Qt5 中如此缓慢?

Len*_*and 2 sqlite qt qtsql qt5 qsqldatabase

Qt5.4中,在Ubuntu14.04 64bit上使用QSqlDatabasesqlite3

首先我打开并调用transaction()数据库。

接下来,我进行了 54 个单独的插入查询,每个都准备好了,每个都在执行后删除。

最后我打电话commit()

所有调用都没有错误地完成,但执行时间仍然很糟糕(54 个微不足道的插入总共大约 500 毫秒)。

我的计算机相当现代,并且具有条带化 SSD 磁盘以提高性能。使用 Sqliteman 访问 sqlite 文件时,速度非常快。

那么是怎么回事呢?

这是插入:

void BottleRigStorage::upsertTag(Tag &tag){
    //ScopedTimer st("query time for tag");
    if(open()){

            QSqlQuery query(db);
            query.prepare("INSERT OR REPLACE INTO tags ("
                          "  id"
                          ", batchID"
                          ", retries"
                          ", good"
                          ", status"
                          ", color"
                          ", firstCheckTimestamp"
                          ", createdTimestamp"
                          ", modifiedTimestamp"
                          ", fulfilledTimestamp"
                          ") VALUES ("
                          "  :id"
                          ", :batchID"
                          ", :retries"
                          ", :good"
                          ", :status"
                          ", :color"
                          ", :firstCheckTimestamp"
                          ", :createdTimestamp"
                          ", :modifiedTimestamp"
                          ", :fulfilledTimestamp"
                          ");");
            query.bindValue(":id", tag.id);//8 chars
            query.bindValue(":batchID", tag.batchID);//8 chars
            query.bindValue(":retries", tag.retries);//int
            query.bindValue(":good",tag.good?1:0);//bool
            query.bindValue(":status", tag.status);//6 chars
            query.bindValue(":color", tag.color);//7 chars
            query.bindValue(":firstCheckTimestamp", tag.firstCheckTimestamp); //long
            query.bindValue(":createdTimestamp", tag.createdTimestamp);//long
            query.bindValue(":modifiedTimestamp", tag.modifiedTimestamp);//long
            query.bindValue(":fulfilledTimestamp", tag.fulfilledTimestamp);//long

            if (query.exec()) {
                //qDebug() << "Successfully updated tag database after "<<st.getIntervalCompleteString();
            }
            else {
                qWarning() << "ERROR: could not upsert tag with id " << tag.id<< ". Reason: "<< query.lastError();
            }
            query.finish();
        }

    else {
        qWarning() << "ERROR: DB not open for upsert tag sqlite3";
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:这里是 open() 要求:

bool BottleRigStorage::open(){
    if(!db.isOpen()){
        if(!db.open()){
            qWarning() << "ERROR: could not open database. Reason: "<<db.lastError();
        }
    }
    return db.isOpen();
}
Run Code Online (Sandbox Code Playgroud)

syn*_*ker 5

  1. 仅使用一次准备。每次创建 QSqlQuery 后,您的代码都会准备查询。您需要在函数外部使用准备创建 QSqlQuery,并且只需在函数中使用值绑定和 sql 查询 exec:

    void BottleRigStorage::upsertTag(Tag &tag){
    //ScopedTimer st("query time for tag");
    if(open()){
            query.bindValue(":id", tag.id);//8 chars
            query.bindValue(":batchID", tag.batchID);//8 chars
            query.bindValue(":retries", tag.retries);//int
            query.bindValue(":good",tag.good?1:0);//bool
            query.bindValue(":status", tag.status);//6 chars
            query.bindValue(":color", tag.color);//7 chars
            query.bindValue(":firstCheckTimestamp", tag.firstCheckTimestamp); //long
            query.bindValue(":createdTimestamp", tag.createdTimestamp);//long
            query.bindValue(":modifiedTimestamp", tag.modifiedTimestamp);//long
            query.bindValue(":fulfilledTimestamp", tag.fulfilledTimestamp);//long
    
            if (query.exec()) {
                //qDebug() << "Successfully updated tag database after "<<st.getIntervalCompleteString();
            }
            else {
                qWarning() << "ERROR: could not upsert tag with id " << tag.id<< ". Reason: "<< query.lastError();
            }
            query.finish();
        }
    
    else {
        qWarning() << "ERROR: DB not open for upsert tag sqlite3";
    }
    
    Run Code Online (Sandbox Code Playgroud)

    }

    这种情况下的查询对象可以是私有成员并创建,例如在数据库初始化之后。

  2. 您可以通过编译指示调整 sqlite 数据库。例如,下一个代码将增加查询的执行:

    m_pDatabase->exec("PRAGMA 同步 = OFF"); m_pDatabase->exec("PRAGMA journal_mode = MEMORY");

    您可以在此处阅读有关此的更多信息

  • 重要提示:我发现这很有启发性 http://beets.io/blog/sqlite-nightmare.html。基本上,sqlite 中有一个错误,在某些情况下,它会休眠几秒钟而不是几毫秒。值得一读。 (2认同)