Qt读写SQLSERVER数据库10W行数据耗时很慢的原因及解决办法

void AppWork::DoWork()
{
    QSqlDatabase    db = QSqlDatabase::addDatabase("QSQLITE", "conn  SQLite");
    db.setDatabaseName("./sqliteDB.db");
    if (!db.open())
    {
        qDebug() << "open db failed!";
    }
    else
    {
        // 创建表
        QSqlQuery query(db);
        query.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='DataBase';");
        if (!query.next())
        {
            if (!query.exec("CREATE TABLE DataBase (id INTEGER PRIMARY KEY, name VARCHAR(20),addr VARCHAR(20))"))
            {
                qDebug() << "Error creating table:" << query.lastError().text();
            }
            else
            {
                qDebug() << "Table created successfully";
            }

        }

        bool success = query.exec("DELETE FROM DataBase");
        if (!success) {
            qDebug() << "Error clearing table:" << query.lastError().text();
        } else {
            qDebug() << "Table cleared successfully";
        }



        bool    bsuccess = false;
        QElapsedTimer    tmpTime,time2;

        // 开始启动事务
        db.transaction();
        tmpTime.start();
     query.prepare("INSERT INTO DataBase(id, name, addr) VALUES(:id, :name, :addr)"); 
        for(int i = 0; i < 100000; i++)
        {
            //query.prepare("INSERT INTO DataBase(id, name, addr) VALUES(:id, :name, :addr)");//放循环外面
            query.bindValue(":id", i); // 绑定id为当前循环的i值
            query.bindValue(":name", "TT"); // 绑定name为字符串"TT"
            query.bindValue(":addr", "TT"); // 绑定addr为字符串"TT"
            bool bsuccess = query.exec();
            if (!bsuccess)
            {
                qDebug() << "Error occurred:" << query.lastError().text();
                break;
            }
        }

        db.commit();
        qDebug()<<"100000条数据耗时:"<<tmpTime.elapsed()<<"ms";

        QVector<QString> nameList;
        // 读取数据
        time2.start();
        query.exec("SELECT * FROM DataBase");
        while (query.next()) {
            int id = query.value(0).toInt();
            QString name = query.value(1).toString();
            nameList << name;

        }

        qDebug() <<"NameList:" << nameList.size()<<"Time :"<<time2.elapsed();
        qDebug() <<"NameList 89999:"<<nameList.at(89999);
        qDebug() <<"NameList 99999:"<<nameList.at(99999);

    }
}

void AppWork::DoSqlServerDB()
{
    QSqlDatabase sqlDB;
    if(QSqlDatabase::contains("MyConnect1"))
    {
        sqlDB = QSqlDatabase::database("MyConnect1");
    }
    else
    {
        sqlDB = QSqlDatabase::addDatabase("QODBC","MyConnect1");
    }
    qDebug()<<"QODBC is Valid?"<<sqlDB.isValid();
    sqlDB.setHostName("localhost");
    sqlDB.setDatabaseName("testDB1228");
    sqlDB.setUserName("sa");
    sqlDB.setPassword("@Password");
    if(!sqlDB.open()){
        qDebug()<<"Error1:"<<sqlDB.lastError().text()<<"Error2:"<<QString::fromUtf8(sqlDB.lastError().text().toStdString().c_str());
    }
    else
    {
        QSqlQuery query(sqlDB);
        query.setForwardOnly(true);
        query.exec("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'myTable'");
        if (query.next()){
            qDebug() << "Table exists";
            if (query.exec("DELETE FROM myTable")){
                qDebug() << "Table cleared successfully";
            }else{
                qDebug() << "Error clearing table:" << query.lastError().text();
            }
        }else{
            qDebug() << "Table does not exist, creating it...";
            if (query.exec("CREATE TABLE myTable (Id INT PRIMARY KEY, name NVARCHAR(50), addr NVARCHAR(50))")) {
                qDebug() << "Table created successfully";
            }else{
                qDebug() << "Error creating table:" << query.lastError().text();
            }
        }
        QElapsedTimer    tmpTime,time2;
        // 开始启动事务
        sqlDB.transaction();
        tmpTime.start();
        query.prepare("INSERT INTO myTable(id, name, addr) VALUES(:id, :name, :addr)");
        for(int i = 0; i < 100000; i++)
        {
            //query.prepare("INSERT INTO myTable(id, name, addr) VALUES(:id, :name, :addr)"); //放循环外面还能快一半速度,可以到5秒
            query.bindValue(":id", i); // 绑定id为当前循环的i值
            query.bindValue(":name", "TT"); // 绑定name为字符串"TT"
            query.bindValue(":addr", "TT"); // 绑定addr为字符串"TT"
            bool bsuccess = query.exec();
            if (!bsuccess){
                qDebug() << "Error occurred:" << query.lastError().text();
                break;
            }
        }
        sqlDB.commit();
        qDebug()<<"100000条数据耗时:"<<tmpTime.elapsed()<<"ms";


        QVector<QString> nameList;
        // 读取数据
        time2.start();
        query.exec("SELECT * FROM myTable");
        while (query.next()) {
            int id = query.value(0).toInt();
            QString name = query.value(1).toString();
            nameList << name;
        }
        qDebug() <<"NameList:" << nameList.size()<<"Time :"<<time2.elapsed();
        qDebug() <<"NameList 89999:"<<nameList.at(89999);
        qDebug() <<"NameList 99999:"<<nameList.at(99999);
    }
}

上述 2 个函数分别用于在sqlite 及sqlserver下 向一个表 中写入和读取 10W行的数据,
运行后发现在sqlite数据库中 写入好事 500ms,读取 耗时 44ms.
而在 sqlserver中 写入耗时11秒,读取也将进 9秒,差别距大,

经过搜索,发现Query有一个setForwardOnly功能,设置为true 后 就可以 一直向前查,不能 返回了,这样性能会有 极大提高,最终 读取 也达到了 90 ms, 而写入是 9秒,没有很大提升。
写入 也使用了事务,不知道为什么提升这么少。

 

posted @ 2024-03-27 16:25  伟大的厨师  阅读(95)  评论(0编辑  收藏  举报