【问题标题】:Why is my sqlite query so slow in Qt5?为什么我的 sqlite 查询在 Qt5 中这么慢?
【发布时间】:2015-09-20 17:24:02
【问题描述】:

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

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

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

【问题讨论】:

  • 你的分析器说什么?
  • 是否有用于 sqlite 的分析器?
  • 可能,但不太可能是 SQLite,更可能与您使用它的方式有关。分析您的应用程序应该揭示减速的位置(或至少给出一个很好的提示)。
  • 被注释掉的ScopedTimer st("query time for tag");代码中的一部分测量了在这个函数中花费的时间,但我想使用分析器我也可以看到子调用。
  • open 有什么功能?顺便说一句,你不需要query.finish();

标签: qt sqlite qt5 qtsql qsqldatabase


【解决方案1】:
  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";
    }
    

    }

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

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

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

    更多关于这方面的信息你可以阅读here

【讨论】:

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

当我有 99 个程序并且每个程序都有 99 个步骤时,我也面临同样的问题,我正在从 CSV 文件中读取 Pendrive 中的数据并将它们插入数据库。它花了超过 5 分钟,但在那之后,我对

ma​​in.cpp

   db.open();
   db.exec("PRAGMA synchronous = OFF");
   db.exec("PRAGMA journal_mode = MEMORY");

并在类上添加了 db commit 以进行插入查询

model.cpp

qDebug()<<"can start a transaction PrgQuery:"<<QSqlDatabase::database().transaction();
query.prepare("insert query");
query.exec();
qDebug()<<"end transaction Step Query:"<<QSqlDatabase::database().commit();

这解决了我的问题并将时间缩短到 10 秒。像无限力量一样快

【讨论】:

    猜你喜欢
    • 2011-03-07
    • 1970-01-01
    • 2011-03-11
    • 2014-08-27
    • 2020-05-03
    • 2017-01-21
    • 2021-03-12
    • 2020-03-19
    • 2014-03-12
    相关资源
    最近更新 更多