QT5导出数据库数据耗时长问题

bool Sqlite3::exportMergeTableData(const QString &currentDate, const QString &csvFilePath)
{
    QString allSql = QString("select bms%1.*,bm%2Voltage.*,bms%3Temperature.* from bms%4 join bms%5Voltage on bms%6.batteryID = bms%7Voltage.batterID join bms%8Temperature on bms%9.batteryID = bms%19Temperature.batteryID").arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate);
    
    qDebug()<<allSql;
    QElapsedTimer timer;
    timer.start();
     
    QSqlQuery query;
    if (!query.exec(allSql)) {
        qDebug() << "查询失败:" << query.lastError().text();
        return false;
    }
    
    QFile csvFile(csvFilePath);
    if (!csvFile..open(QIODevice::WriteOnly | QIODevice::Text)) {
		qDebug() << "无法创建 CSV 文件:" << csvFile.errorString();
        return false;
    }
    
    QTextStream out(&csvFile);

	for (int i = 0; i < query.record().count(); ++i) {
		out << query.record().fieldName(i);
        if (i< query.record().count() - 1)
            out << ",";
    }
    out << "\n";

	while (query.next()) {
        for (int i = 0; i  < query.record().count(); ++i) {
            out << query.value(i).toString();
            if (i  < query.record().count() - 1)
                out << ",";
        }
        out << "\n";
    }
	csvFile.close();
    qDebug()<<"导出时间:"<<timer.elapsed();
    db.close();
    qDebug() << "表" << tableName << "已成功导出到" << csvFilePath;
    return true;
}

概述:

这是一个传入数据表的日期和文件保存路径,然后根据日期组合成数据表,在把三个数据表的数据合并后导出成csv文件的函数,经过优化导出6000行数据,从87678ms缩短到563ms

问题:

导出一个6000行的数据,需要耗时87678ms,非常慢,而且没有使用线程,导致用户界面卡顿严重。正常的最大导出数据有8w多行,更卡,无法正常使用。

分析问题:

经过测试,发现问题出现在这段代码里面的,query.value(i).toString();位置。每次都是单个字段读取,数据表数据又非常大,所以这里耗时非常大,但这里就大概需要82655ms。

	while (query.next()) {
        for (int i = 0; i  < query.record().count(); ++i) {
            out << query.value(i).toString();
            if (i  < query.record().count() - 1)
                out << ",";
        }
        out << "\n";
    }

问题处理:

优化这段代码,改成这种方式,优化后6000行代码,只需要563ms,优化思路如下:
1、减少query.value(i) 的调用次数:
使用QSqlRecord一次性获取整行数据,而不是逐列调用
2、批量写入csv文件,积累多行后一起写入,减少IO的开销

进一步优化:

如果数据量非常庞大,可以考虑:
1、分页查询:使用LIMIT和OFFSET分批次读取数据
2、多线程处理:将数据读取和数据写入分离到不同的线程

优化后的方案:

bool Sqlite3::exportMergeTableData(const QString &currentDate, const QString &csvFilePath)
{
    QString allSql = QString("select bms%1.*,bm%2Voltage.*,bms%3Temperature.* from bms%4 join bms%5Voltage on bms%6.batteryID = bms%7Voltage.batterID join bms%8Temperature on bms%9.batteryID = bms%19Temperature.batteryID").arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate).arg(currentDate);
    
    qDebug()<<allSql;
    QElapsedTimer timer;
    timer.start();
     
    QSqlQuery query;
    if (!query.exec(allSql)) {
        qDebug() << "查询失败:" << query.lastError().text();
        return false;
    }
    
    QFile csvFile(csvFilePath);
    if (!csvFile..open(QIODevice::WriteOnly | QIODevice::Text)) {
		qDebug() << "无法创建 CSV 文件:" << csvFile.errorString();
        return false;
    }
    
    QTextStream out(&csvFile);

	for (int i = 0; i < query.record().count(); ++i) {
		out << query.record().fieldName(i);
        if (i< query.record().count() - 1)
            out << ",";
    }
    out << "\n";

    const int bufferSize = 1000;
    QString buff;
    int rowCount = 0;
    QSqlRecord record = query.record();
    int columnCount = record.count();
    while (query.next()) {
        QString rowData;
        for(int i = 0;i<columnCount;++i){
            rowData.append(query.value(i).toString());
            if(i<columnCount-1){
                rowData.append(",");
            }
        }
        buffer.append(rowData).append("\n");
    	rowCount++;
    	if(rowCount%bufferSize == 0){
            out<<buffer;
            out.flush();
            buffer.clear();
        }
    }
    if(!buffer.isEmpty()){
        out<<buffer;
    }
    
	csvFile.close();
    qDebug()<<"导出时间:"<<timer.elapsed();
    db.close();
    qDebug() << "表" << tableName << "已成功导出到" << csvFilePath;
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值