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?
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. –
Die Bind-Aufrufe kehren fast sofort zurück. – Silicomancer