У меня есть код C ++, который анализирует файлы и обновляет базу данных MySQL в соответствии с содержимым этих файлов.
Я запускаю свой код в Windows 10 с MySQL 5.7, и моя база использует движок InnoDB. Вызовы MySQL выполняются через мою собственную оболочку вокруг libmysql.
В попытке оптимизировать этот код, я добавляю запросы на обновление в буфер до достижения максимального размера буфера, затем отправляю весь буфер (содержащий N обновлений) одновременно. Весь этот процесс выполняется внутри одной транзакции.
Вот как выглядит мой код:
MySQLWrapper.StartTransaction();
string QueryBuffer = "";
// Element count is the number of elements parsed from the files
for( int i = 0 ; i < ElementCount ; ++i )
{
bool FlushBuffer =
( i> 0 && ! (( i + 1 ) % N) ) ||
( i == ElementCount - 1 ); // determines if we have reached the buffer max number of requests
QueryBuffer += "INSERT INTO mytable (myfield) VALUES (" Element[ i ] ");";
if( FlushBuffer )
{
MySQLWrapper.SendRequest( QueryBuffer );
QueryBuffer.assign("");
}
}
MySQLWrapper.Commit();
Реализация SendRequest (строка запроса) будет в основном:
void SendRequest(string Request)
{
mysql_query( SQLSocket, Request.c_str())
}
Однако при фиксации транзакции транзакция была прервана: MySQL указывает на то, что состояние неверно для совершения транзакции. Я пытался сделать то же самое, но отправлять запросы только по одному, и эта ошибка не происходит в момент фиксации.
Итак, мои 2 вопроса:
Вместо нескольких INSERT создайте один INSERT с несколькими значениями. IOW, до цикла,
иметь INSERT INTO TABLE (columns)
, затем внутри цикла, добавить (values),
для каждого набора значений.
MySQLWrapper.StartTransaction();
string QueryBuffer = "INSERT INTO mytable (myfield) VALUES ";
// Element count is the number of elements parsed from the files
for( int i = 0 ; i < ElementCount ; ++i )
{
bool FlushBuffer =
( i> 0 && ! (( i + 1 ) % N) ) ||
( i == ElementCount - 1 ); // determines if we have reached the buffer max number of requests
QueryBuffer += "(" Element[ i ] ")";
if( flushbuffer ) {
QueryBuffer += ";";
} else {
QueryBuffer += ",";
}
if( FlushBuffer )
{
MySQLWrapper.SendRequest( QueryBuffer );
QueryBuffer.assign("");
}
}
MySQLWrapper.Commit();
Результирующий оператор SQL будет выглядеть примерно так:
INSERT INTO mytable
(myfield)
VALUES
(1),
(2),
(3),
(3);
Других решений пока нет …