2013-07-05 68 views
2

我正在研究涉及大量sql查询的Qt(C++)项目。基本上它是一个函数update(),它被称为〜1000次。在我的系统中,每次通话大约需要25 - 30ms,总共可以执行30秒的总执行时间。我相信这个例程可以优化,从而减少时间消耗,但不知道如何优化。这里是功能 -如何优化涉及大量sql查询的Qt代码块?

void mediaProp::update(){ 
static QSqlQuery q1, q2, q3; 
static bool firstCall = true; 
static QString stable; 
QString table = this->type+"s"; 
if(firstCall){ 
    stable = table; 
    q1.prepare("SELECT id FROM titles WHERE lower(title)= lower(:a) AND type = :b COLLATE NOCASE"); 
    q2.prepare("INSERT INTO " + table + "(pic_id, score) VALUES (0, 0)"); 
    q3.prepare("INSERT INTO titles (id, type, title) VALUES (:a, :b, :c)"); 
    firstCall = false; 
} 
else if(stable != table){ 
    stable = table; 
    q2.prepare("INSERT INTO " + table + "(pic_id, score) VALUES (0, 0)"); 
} 
q1.bindValue(":a", this->title); 
q1.bindValue(":b", dbEnums(this->type)); 
q1.exec(); 
q1.last(); 
int size = q1.at() + 1; 

if(size > 0){ 
    q1.first(); 
    this->id = q1.value("id").toInt(); 
} 
else if(!this->title.trimmed().isEmpty()){ 
    q2.exec(); 
    this->id = q2.lastInsertId().toUInt(); 
    q3.bindValue(":a", this->id); 
    q3.bindValue(":b", dbEnums(this->type)); 
    q3.bindValue(":c", this->title); 
    q3.exec(); 
} 
else{ 
    this->id = 0; 
} 

}

任何建议或帮助将是真是太神奇了! 谢谢:)

编辑 - 作为建议的勒芒Danvin,我所做的更改的功能和上面更新它。

EDIT2 - Yohan Danvin的理念很聪明,我也确信使用准备好的语句作为静态变量会优化例程。但它不符合我们的预期。整个程序花费的时间更多,而不是花时间。准备好的陈述让事情变得更糟!但后来有很多的挖掘后,我发现为什么它是所谓

THE PROCEDURE TOOK 25 MILLISECONDS IN AVERAGE 
AFTER USING Yohan's STATIC PREPARED STATEMENT MAPPING PROCEDURE- IT TOOK 27ms IN AVG 

为了记录在案,我是用一个文件作为我的数据库不是记忆。每次执行INSERT查询时,QSqlQuery都会创建一个临时转储文件并将其附加到主数据库文件中。与内存相比,访问文件非常耗时,导致插入速率慢了25ms。我想当我使用Yohan的概念时,由于功能开销等原因需要更多时间。如果我错了,请告诉我!最后我碰到http://www.sqlite.org/pragma.html和改变了一些编译参数 -

QSqlQuery("PRAGMA journal_mode = OFF"); 
QSqlQuery("PRAGMA synchronous = OFF"); 

这工作就像魅力!执行速度从每次例行呼叫25毫秒降至每3次例行呼叫1毫秒。这是一个巨大的差距!基本上设置pragma journal_mode = OFF告诉SQLITE不要创建一个单独的临时转储文件,并且PRAGMA synchronous = OFF在执行所有查询后将更改应用于数据库。可能是,通过使用临时内存数据库。如果我提出了一个错误的观点,请让我知道。

我很高兴现在的例程是145X更快!

+1

假设您的数据库有事务,您是在执行1000个事务还是只有一个?这在性能方面完全不同。 –

回答

2

你想prepare每个查询/语句只有一次,而不是更多。否则,DBMS每次都会重新计算执行计划,这很耗时。

也许你应该实现的方式,以确保这是在你的应用程序中所有的查询/报表完成的,就像这样:

QSqlQuery& prepareQuery(const QString& query) 
{ 
    static QMap<QString, QSqlQuery> queries; 

    if (!queries.contains(query)) 
    { 
     // not found, insert the query in the map and "prepare" it 
     queries[query].prepare(query); 
    } 

    return queries[query]; 
} 

有了这个可用,现在在你的榜样的选择是这样的:

QSqlQuery& q = prepareQuery("SELECT id FROM titles WHERE lower(title)= lower(:a) AND type = :b COLLATE NOCASE"); 
q.bindVariable... 

执行此为2点的插入,以及(即使一个具有可变的表名,类SqlQuery将自动创建并针对每个不同的表名的方法制备)。

[N.B.:请注意,如果在多线程环境中工作,您必须确保同一个QSqlQuery对象不被两个不同的线程同时使用]

+0

感谢您的时间!我的做法有点不同。请参阅问题中的更新代码。你的逻辑完全有道理!但是令我震惊的是,这些变化让这个功能运行得更慢!任何想法? – Killswitch

+0

它绝对不应该慢,不。也许你在重构时引入了一个错误?我更新了我的答案。我建议你回到你原来的代码,并尝试新的解决方案,这需要更少的更改并提高可读性。 –