Перенос записей из одной базы данных в mysql очень медленный с Delphi и Firedac.

Мне нужно перенести несколько записей более 100000 из базы данных Advantage Local в Mysql (local).

Я тестирую этот код, но его результаты очень и очень медленные. Более 2 часов для переноса 120000 записей.

Мне нужна помощь, чтобы улучшить скорость, возможно, изменив код или некоторые свойства firedac.

Код очень простой. Я запрашиваю все записи из таблицы Advantable, делаю цикл для каждой записи и вставляю в локальную базу данных mysql.

    // ADVANTAGE TABLE
    DM.Qry_Usb.SQL.Clear;
    DM.Qry_USB.SQL.Add( 'Select * from Cabezal' );
    DM.Qry_USB.SQL.Add( 'order by Fecha, Pedido' );
    DM.Qry_USB.Open;

    while not DM.Qry_USB.Eof do
    begin

        DM.FDQuery.SQL.Clear;    // MYSQL DB
        DM.FDQuery.SQL.Add( 'Insert Into Cabezal ' );
        DM.FDQuery.SQL.Add( '( Correla, Fecha, Hora, Cliente, Pedido, Direccion, ');
        DM.FDQuery.SQL.Add( 'Entre, yEntre, Estado, Total, PedidoxWeb ) ' );
        DM.FDQuery.SQL.Add( 'Values ( ' );
        DM.FDQuery.SQL.Add( IntToStr( DM.Qry_USB.FieldByName('Correla').AsInteger ) + ',' );
        DM.FDQuery.SQL.Add( QuotedStr( FormatDateTime( 'DD.MM.YYYY', DM.Qry_Usb.FieldByName('Fecha').AsDateTime ) ) + ',' );
        DM.FDQuery.SQL.Add( QuotedStr( FormatDateTime( 'HH:MM:SS', DM.Qry_Usb.FieldByName('Hora').AsDateTime ) ) + ',' );
        DM.FDQuery.SQL.Add( IntToStr( DM.Qry_USB.FieldByName('Cliente').AsInteger ) + ',' );
        DM.FDQuery.SQL.Add( IntToStr( DM.Qry_USB.FieldByName('Pedido').AsInteger ) + ',' );
        DM.FDQuery.SQL.Add( QuotedStr( DM.Qry_USB.FieldByName('Direccion').AsString ) + ',' );
        DM.FDQuery.SQL.Add( QuotedStr( DM.Qry_USB.FieldByName('Entre').AsString ) + ',' );
        DM.FDQuery.SQL.Add( QuotedStr( DM.Qry_USB.FieldByName('YEntre').AsString ) + ')' );
        DM.FDQuery.ExecSQL;

        DM.Qry_USB.Next;

    end;
    DM.FDConnection.Commit;

Я изменяю код для использования параметров, но все еще не могу его проверить.

Что еще я могу изменить, чтобы сделать этот код быстрее??

Заранее большое спасибо.

Лучшие регады.


person Leo Bidi    schedule 11.10.2017    source источник
comment
Используйте 1_. В вашем коде есть по крайней мере два этих недостатка: повторение набора данных с помощью курсора и повторяющаяся подготовка команды (вы можете выполнить итерацию базового исходного хранилища данных, а для цели подготовить команду один раз и изменить только параметры). Тем не менее, TFDBatchMove является компонентом именно для этой цели.   -  person Victoria    schedule 11.10.2017
comment
Что говорит @Victoria. Если вы должны сделать это со своим циклом по какой-либо причине. не делайте все эти вызовы FieldByName для каждой записи в Qry_USB — найдите их и назначьте их локальным переменным поля до начала цикла. И фиксируйте целевую транзакцию каждые несколько десятков строк.   -  person MartynA    schedule 11.10.2017
comment
И перестаньте очищать SQL между строками. Используйте параметры, настройте SQL один раз перед циклом, а затем просто установите значения параметров и выполните SQL внутри цикла. Это позволяет серверу оптимизировать его, настроив (идентифицируя параметры, создав для них заполнители) и скомпилировав SQL один раз, а затем кэшировав этот скомпилированный оператор. Говорить Я модифицирую, чтобы использовать параметры, но все еще не могу это проверить, не имеет смысла. Вы модифицируете его, как я указал, а затем выполняете код, и когда это будет сделано, вы закончите.   -  person Ken White    schedule 12.10.2017
comment
Хорошо, спасибо всем за ваши ответы. Я попробую то, что вы упомянули, а затем дам вам знать.   -  person Leo Bidi    schedule 12.10.2017
comment
Анализировать особо нечего. Забудьте о своем коде, о том, что мы говорили, и научитесь использовать TFDBatchMove. Он будет внутренне использовать метод массива DML, который должен быть самым быстрым способом перемещения данных из одной СУБД в другую. Он достаточно гибкий, чтобы удовлетворить вашу задачу. @Ken, вставка массива DML также может значительно улучшить эту задачу (для MySQL она нативная). В данном случае это было бы изобретением велосипеда.   -  person Victoria    schedule 14.10.2017


Ответы (1)


Пример решения аналогичной проблемы.

http://docwiki.embarcadero.com/CodeExamples/Sydney/en/FireDAC.TFDQuery.Batch_Sample

  FDQuery1.SQL.add('sELECT * from cars');
  FDQuery1.open;


  FmMain.FDConnection1.StartTransaction;
  FDQuery2.sql.clear;
  FDQuery2.sql.add('INSERT INTO tributosasociados (id,NroContrib, CodTributo, CodImponible,descripcion,BAseImponible,Alicuota,FechaAlta,activo )');
  FDQuery2.sql.Add('VALUES(null, :NroContrib,:CodTributo,:CodImponible, :descripcion, :BAseImponible,:Alicuota,:FechaAlta,:activo)');


  FDQuery2.Params.ArraySize := FDQuery1.RecordCount;
   i := 0;
  while not FDQuery1.eof do
   begin
     FDQuery2.ParamByName('CodTributo').AsIntegers[i] := 3;
     FDQuery2.ParamByName('NroContrib').AsIntegers[i] := FDQuery1.FieldByName('NroContrib').AsInteger;
     FDQuery2.ParamByName('CodImponible').AsStrings[i] := FDQuery1.FieldByName('dominio').AsString;
     FDQuery2.ParamByName('descripcion').AsStrings[i] := FDQuery1.FieldByName('descripcion').AsString +' / '+ FDQuery1.FieldByName('anio').AsString;
     FDQuery2.ParamByName('BAseImponible').AsFloats[i] := FDQuery1.FieldByName('valuacion').AsFloat;
     FDQuery2.ParamByName('Alicuota').AsFloats[i] := 1.7; // FDQuery1.FieldByName('****Ver Alicuta BUTA****').AsFloat;
     FDQuery2.ParamByName('FechaAlta').AsdateTimes[i] := FDQuery1.FieldByName('FechaAlta').AsdateTime;
     FDQuery2.ParamByName('activo').AsIntegers[i] := 1;

     FDQuery1.next;
     i := i+1;
   end;

  FDQuery2.Execute(FDQuery2.Params.ArraySize);

  FmMain.FDConnection1.Commit;

 FDQuery1.close;
 FDQuery2.close;
 ShowMessage( intToStr(i) );
person Silvio Parada    schedule 10.10.2020
comment
Не могли бы вы уточнить свой ответ и как это решает заданный вопрос? - person Skully; 11.10.2020