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秒,没有很大提升。
写入 也使用了事务,不知道为什么提升这么少。