2014-09-10 3 views
7

Ich verwende das SQL-Modul von Qt 5.3.1 (Win 7, VS2013), um Daten in eine MySQL 5.6-Datenbank einzufügen. Nachdem ich einige Leistungsprobleme festgestellt habe, führe ich drei Testcode-Snippets aus und messe deren Laufzeit, um die SQL-Performance besser zu verstehen. Das Ergebnis ist verwirrend.Leistung bei Verwendung des Batch-Modus von Qt/MySQL

Zum Testen verwendete ich eine "Test" -Tabelle, die eine VARCHAR-Spalte "test" und eine eindeutig erhöhte ID für jede Zeile enthielt.

Der erste Schnipsel sieht im wesentlichen wie folgt aus:

const QString uploadQueryString("INSERT INTO test (test) VALUES ('%1')"); 
for (int i=0; i<1000; i++) 
{ 
    QSqlQuery uploadQuery(uploadQueryString.arg("A: test text"), dataBase); 
    if (uploadQuery.lastError().isValid()) 
    { 
     qDebug() << tr("Query execution failed (%1)").arg(uploadQuery.lastError().text()); 
    } 
} 

Die zweite wie folgt aus:

const QString uploadQueryString("INSERT INTO test (test) VALUES %1"); 

QStringList values; 
for (int j=0; j<1000; j++) 
{ 
    values.append("\"B: test text\""); 
} 

QString valuesString = "("+ContainerToString(values, "), (")+")"; 

QSqlQuery uploadQuery(uploadQueryString.arg(valuesString), dataBase); 
if (uploadQuery.lastError().isValid()) 
{ 
    qDebug() << tr("Query execution failed (%1)").arg(uploadQuery.lastError().text()); 
} 

Die dritte wie folgt aus:

const QString uploadQueryString("INSERT INTO test (test) VALUES (:values)"); 

QVariantList values; 
for (int j=0; j<1000; j++) 
{ 
    values.append("C: test text"); 
} 

QSqlQuery batchQuery(dataBase); 
if (batchQuery.prepare(uploadQueryString)) 
{ 
    batchQuery.bindValue(":values", values); 

    if (!batchQuery.execBatch()) 
    { 
     qDebug() << tr("Batch query execution failed (%1)").arg(batchQuery.lastError().text()); 
    } 
} 
else 
{ 
    qDebug() << tr("Unable to prepare batch query"); 
} 

I jede dieser Schnipsel ausgeführt (einschließlich öffnen/schließen code) 10 mal:

1. 10x1000 basic inserts 
Ticks delta: 318617 ms; Kernel delta: 358 ms; User delta: 1201 ms; Process delta 1559 ms 

2. 10x1000 by value list insert 
Ticks delta: 3011 ms; Kernel delta: 0 ms; User delta: 46 ms; Process delta 46 ms 

3. 10x1000 by batch insert 
Ticks delta: 631679 ms; Kernel delta: 811 ms; User delta: 998 ms; Process delta 1809 ms 

"Ticks delta" ist die Zeit, die für jedes Snippet benötigt wird. "Kernel delta" und "User delta" ist die tatsächlich aktive Benutzer- und Kernel-Verarbeitungszeit, während "Process delta" die Summe aus Kernel und Benutzerzeit ist.

Das erste Ergebnis ist wie erwartet: Es braucht viel Zeit (insbesondere wegen Latenzen), um 10x1000 einzelne Abfragen auszuführen.

Das zweite Ergebnis ist auch wie erwartet: Es ist sehr schnell eine einzige Abfrage auszuführen, die alle Zeilen gleichzeitig enthält.

Leider verwirrt mich das dritte Ergebnis total: Ich habe erwartet, dass der Batch-Modus viel schneller ist! Selbst im schlimmsten Fall (wenn die Batch-Ausführung vom Treiber mit einzelnen Abfragen simuliert wird, wie es die Qt-Dokumentation sagt) sollte es genauso langsam sein wie das erste Snippet. In der Tat braucht es die doppelte Zeit!

Was macht Batch-Ausführung tatsächlich in Qt/MySQL? Gibt es eine Möglichkeit, die Batch-Ausgabe-Performance zu verbessern? Wie ist es möglich, dass execBatch() viel schlechter läuft als die Ausführung einzelner Abfragen?

+0

Können Sie das 'bind_value()' Stück in jedem von ihnen? Ich verstehe den dritten Ansatz nicht vollständig, aber es scheint ungewöhnlich, ein String-Listenobjekt an einen SQL-Parameter zu binden. Möglicherweise befinden sich auf der Clientseite zusätzliche Analyseebenen, die Sie nicht sehen. –

+0

Die Bind-Aufrufe kehren fast sofort zurück. – Silicomancer

Antwort

1

QMYSQL unterstützt BatchExec nicht.

Sie können QSqlDriver :: hasFeature (QSqlDriver :: BatchOperations) verwenden, um zu überprüfen, ob ein Treiber Batchexec unterstützt.

Sie können auch die Quelle überprüfen in QT_SRC/src/SQL/drivers/mysql/qsql_mysql.cpp

Bool QMYSQLDriver :: hasFeature (DriverFeature f) const

es gerade falsch.

+0

Es scheint, dass Sie Recht haben. Ich nahm an, Qt würde Batch-Operationen unterstützen, wenn die Datenbank dies tut. AFAIK MySQL unterstützt es. Was für eine Schande. Dennoch frage ich mich, warum simulierte Batch-Operationen viel langsamer sind als einzelne Abfragen. Hast du eine Idee warum? – Silicomancer