Я использую SQL-модуль Qt 5.3.1 (Win 7, VS2013) для вставки данных в базу данных MySQL 5.6. После того, как я заметил некоторые проблемы с производительностью, я выполнил три фрагмента тестовых кодов и измерил их время выполнения, чтобы лучше понять производительность SQL. Результат запутан.Производительность при использовании пакетного режима Qt/MySQL
Для тестирования я использовал «тестовую» таблицу, содержащую столбец VARCHAR «test» и уникально увеличенный идентификатор для каждой строки.
Первый фрагмент выглядит по существу, как это:
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());
}
}
Второй так:
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());
}
Третий так:
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");
}
я выполнил каждый из этих фрагментов (включая код открытия/закрытия) 10 раз:
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" - это время, необходимое для каждого фрагмента. «Дельта ядра» и «Пользовательская дельта» - фактически активное время обработки пользователя и ядра, а «Дельта процесса» - это сумма времени ядра и пользователя.
Первый результат в ожидании: для выполнения 10x1000 одиночных запросов требуется много времени (особенно из-за задержек).
Второй результат также похож на ожидаемый: очень быстро выполнить один запрос, содержащий все строки одновременно.
Увы, третий результат полностью меня смущает: я ожидал, что пакетный режим будет намного быстрее! Даже в худшем случае (если пакетное исполнение моделируется драйвером с использованием одиночных запросов, например, как описано в документации Qt), он должен быть столь же медленным, как и первый фрагмент. На самом деле это требуется в два раза больше времени!
Что делает пакетное выполнение на самом деле в Qt/MySQL? Есть ли способ улучшить производительность выработки пакетов? Как возможно, что execBatch() выполняет намного хуже, чем выполнение одиночных запросов?
Можете ли вы обработать произведение 'bind_value()' в каждом из них? Я не совсем понимаю третий подход, но кажется необычным связывать объект списка строк с параметром SQL. На стороне клиента могут быть дополнительные слои синтаксического анализа, которые вы не видите. –
Прямые звонки возвращаются почти сразу. – Silicomancer