2013-07-05 66 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

它絕對不應該慢,不。也許你在重構時引入了一個錯誤?我更新了我的答案。我建議你回到你原來的代碼,並嘗試新的解決方案,這需要更少的更改並提高可讀性。 –