2

膨大な数の SQL クエリを含む Qt(C++) プロジェクトに取り組んでいます。基本的に、これは~ 1000update()呼び出される関数です。私のシステムでは、すべての呼び出しに約 25 ~ 30 ミリ秒かかるため、合計実行時間は 30 秒と膨大になります。このルーチンを最適化して時間の消費を減らすことができると思いますが、最適化の方法がわかりません。ここに関数があります-

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;
}

}

どんな提案や助けも本当に素晴らしいでしょう! ありがとう :)

編集- Yohan 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 は一時的なダンプ ファイルを作成し、それをメイン データベース ファイルに追加していました。メモリとは対照的にファイルへのアクセスは非常に時間がかかるため、挿入速度は 25 ミリ秒と遅くなりました。Yohan のコンセプトを使用したときは、関数のオーバーヘッドなどでもう少し時間がかかったと思います。間違っていたら教えてください。最後に、私はhttp://www.sqlite.org/pragma.htmlに出会い、いくつかのプラグマパラメーターを変更しました-

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

そして、それは魅力のように機能しました!実行速度は、ルーチン コールあたり 25 ミリ秒から 3 ルーチン コールあたり 1 ミリ秒に減少しました。それは大きなギャップです!基本的に を設定すると、 pragma journal_mode = OFFSQLITE に個別の一時ダンプ ファイルを作成しないように指示しPRAGMA synchronous = OFF、すべてのクエリが実行された後に変更をデータベースに適用します。場合によっては、一時的なインメモリ データベースを使用します。私が間違っている点を指摘した場合はお知らせください。

ルーチンが145 倍高速になったことを嬉しく思います。

4

1 に答える 1

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 が自動的に作成され、異なるテーブル名ごとに準備されます)。

[NB: マルチスレッド環境で作業する場合、同じ QSqlQuery オブジェクトが 2 つの異なるスレッドで同時に使用されないようにする必要があることに注意してください]

于 2013-07-05T00:17:04.017 に答える