Перейти к содержанию
Fire Monkey от А до Я

Александр Журавлев

Пользователи
  • Постов

    4
  • Зарегистрирован

  • Посещение

Сообщения, опубликованные Александр Журавлев

  1. в общем, попробовал переписать код с использованием TFDMemTable:

    var mtL, mtR, mt: TFDMemTable;
    d,d1,d2: tdatetime;
    s,id: string;
    c:char;  idR, m, line, status, InA, InC, OutA, OutC, h:int64;
    begin
      c:=chr(39);
      mtL:=TFDMemTable.Create(nil);  mtR:=TFDMemTable.Create(nil);
    
      FDQueryL[0].Connection:=FDConnectL[0];
      FDQueryR[0].Connection:=FDConnectL[0];
      FDQueryL[0].FetchOptions.Unidirectional := False;
      FDQueryR[0].FetchOptions.Unidirectional := False;
      FDQueryL[0].Sql.Text := 'SELECT * FROM source_table;';
      FDQueryL[0].Open;
      FDQueryL[0].FetchAll;
      FDQueryR[0].Sql.Text := 'SELECT * FROM destination_table;';
      FDQueryR[0].Open;
      FDQueryR[0].FetchAll;
    
    //  mtL.Data:=FDQueryL[0].Data;
    //  mtR.Data:=FDQueryR[0].Data;
      mtL.CopyDataSet(FDQueryL[0], [coStructure, coRestart, coAppend] );
      mtR.CopyDataSet(FDQueryR[0], [coStructure, coRestart, coAppend] );
      mtL.Open;
      mtR.Open;
    
      mtL.DisableControls;
      mtR.DisableControls;
    
      with mtR do
      begin
        LogChanges := False;
        FetchOptions.RecsMax := 300000;  //Sample value
        ResourceOptions.SilentMode := True;
        UpdateOptions.LockMode := lmNone;
        UpdateOptions.LockPoint := lpDeferred;
        UpdateOptions.FetchGeneratorsPoint := gpImmediate;
      end;
      mtR.BeginBatch;
      
      idR:=0;
      d:=EncodeDate(2019,6,1)+EncodeTime(1,0,0,0);   d1:=d;
      while d<now do
      begin
        for line := 4 to 20 do
        begin
          //выбитаем все что в 1 часе
          mtL.Filtered := False;
          //не обращайте внимания на кривизну кода фильтра
          mtL.Filter := '(ID_CL='+inttostr(line)+') AND '+
                        '(TimeFrom >= '+c+DateTimeToStr(d)+c+
                        ') AND ('+
                        'TimeFrom < '+c+FormatDateTime('dd.mm.yyyy h:mm:ss', IncSecond(d, 3599))+c+')';
          mtL.Filtered := true;
          //считаем сумму минут
          m:=0; InA:=0; InC:=0; OutA:=0; OutC:=0;
          mtL.First;
          while (not mtL.Eof) do
          begin
            m:=m+SecondOfTheDay(mtL.Fields[2].AsDateTime)-SecondOfTheDay(mtL.Fields[1].AsDateTime);
            InA:=InA + mtL.Fields[4].AsInteger;     InC:=InC + mtL.Fields[5].AsInteger;
            OutA:=OutA + mtL.Fields[6].AsInteger;   OutC:=OutC + mtL.Fields[7].AsInteger;
            Application.ProcessMessages;
            mtL.Next;
          end;
          //выставляем статус пакету
          if m=3600 then status:=1 else status:=0;
          if m<>0 then //добавляем записб в приемник
          begin
            with mtR do
            begin
              Append;
              Fields[0].AsInteger := idR;
              Fields[1].AsDateTime := d;
              Fields[2].AsDateTime := d+EncodeTime(1,0,0,0);
              Fields[3].AsInteger := line;
              Fields[4].AsInteger := InA;         Fields[5].AsInteger := InC;
              Fields[6].AsInteger := OutA;        Fields[7].AsInteger := OutC;
              Post;
            end;
            idR:=idR+1;
          end;
        end;
        d:=RecodeMilliSecond(d, 0);
        d:=IncSecond(d,3600);
        Application.ProcessMessages;
      end;
      mtR.EndBatch;
    
      mtL.EnableControls;
      mtR.EnableControls;
    
      FDQueryR[0].Close;
      FDQueryR[0].CopyDataSet(mtR);
      FDQueryR[0].Open;
    
      mtL.Free;     mtR.Free;     

    Результата нет - памяти жрет 170 Мб (вместо 5), а работает так же медленно.

    помогите. что я делаю не так?

  2. Добрый день. только начал разбираться с базами данных и возникли сложности при обработке больших объемов.

    в таблице есть записи, некоторые числовые данные за несколько минутный интервал. поля TimeFrom и TimeTo есть соответственно, по которым ясен интервал.

    Нужно собрать таблицу почасовых данных. где каждая запись - сумма данных за 1 час.

      c:=chr(39);
      FDQueryL[0].DisableControls;  DBGridL0.DataSource.DataSet.DisableControls;
      DBGridL0.Visible:=false;
    
      idR:=0;
      d:=EncodeDate(2017,1,1)+EncodeTime(1,0,0,0);   d1:=d;
      while d<now do
      begin
        //for line := 4 to 20 do
        begin
          //выбитаем все что в 1 часе
          FDQueryL[0].Open('SELECT * FROM '+valL0.Values['Table']+' '+
            'WHERE ID_CL='+inttostr(line)+' AND '+
            'TimeFrom BETWEEN '+
            c+FormatDateTime('yyyy-mm-dd h:mm:ss', d)+c+
            ' AND '+
            c+FormatDateTime('yyyy-mm-dd h:mm:ss', IncSecond(d, 3599))+c+';');
          //считаем сумму минут
          m:=0; InA:=0; InC:=0; OutA:=0; OutC:=0;
          DBGridL0.DataSource.DataSet.First;
          while (not DBGridL0.DataSource.DataSet.Eof) do
          begin
            m:=m+SecondOfTheDay(DBGridL0.DataSource.DataSet.Fields[2].AsDateTime)-SecondOfTheDay(DBGridL0.DataSource.DataSet.Fields[1].AsDateTime);
            //суммирование непосредственно нужных данных      
            InA:=InA + DBGridL0.DataSource.DataSet.Fields[4].AsInteger;
            InC:=InC + DBGridL0.DataSource.DataSet.Fields[5].AsInteger;
            OutA:=OutA + DBGridL0.DataSource.DataSet.Fields[6].AsInteger;
            OutC:=OutC + DBGridL0.DataSource.DataSet.Fields[7].AsInteger;
            Application.ProcessMessages;
            DBGridL0.DataSource.DataSet.Next;
          end;
          //выставляем статус новой часовой записи. нолные данные или нет
          if m=3600 then status:=1 else status:=0; //если запись состоит из 3600 секунд данных 
          if m<>0 then //добавляем запись в приемник, если данные вообще есть 
          begin
            FDQueryL[0].ExecSQL(
              'INSERT INTO xxx (ID, TimeFrom, TimeTo, ID_CL, InA, InС, OutA, OutC, Status) VALUES ('+
                  c + IntToStr(idR) + c + ', ' +    //ID
                  c + FormatDateTime('yyyy-mm-dd h:mm:ss', d) + c + ', ' +                     //TimeFrom
                  c + FormatDateTime('yyyy-mm-dd h:mm:ss', d+EncodeTime(1,0,0,0)) + c + ', ' +                   //TimeTo
                  c + IntToStr(line) + c +                         ', ' +                   //ID_CountingLine
                  c + IntToStr(InA) + c +                          ', ' +
                  c + IntToStr(InC) + c +                          ', ' +
                  c + IntToStr(OutA) + c +                         ', ' +
                  c + IntToStr(OutC) + c +                         ', ' +
                  c + IntToStr(status) + c +                       '); ');
            idR:=idR+1;
          end;
        end;
        d:=RecodeMilliSecond(d, 0); // это чтобы не накапливалась ошибка  инкремента дат
        d:=IncSecond(d,3600);
        Application.ProcessMessages;
      end;
    
      FDQueryL[0].EnableControls;  DBGridL0.DataSource.DataSet.EnableControls;
      DBGridL0.Visible:=true;

     

    Вот так костылём кое-как делаю, как видно я тут и прям по DBGrid лопачу и FDQuery, что на самом деле с одной базой связано, одним дата сетом.  данные за 1 год обрабатываются СУТКИ!

    Я правильно понимаю, что делаю это в режиме LiveDataWindowMode ? Я даже не использую FDTable вообще.

    Толковой статьи как правильно организовать обработку не нашёл. только какие-то отдельные статьи.

    пока что в них увидел такие советы, как кэширование:

    FDQuery1.CachedUpdates := True;
    ...
    FDQuery1.Edit;
    ...
    FDQuery1.Post;
    ...
    FDQuery1.Append;
    ...
    FDQuery1.Post;
    ...
    FDQuery1.ApplyUpdates;
    FDQuery1.CommitUpdates;
    FDQuery1.CachedUpdates := False;

    Но тут мне не понятно сколько таких команд Append может быть максимум? как часто делать ApplyUpdates...

    Видел советы использовать TFDMemTable. Но я т.к. новичок не понимаю даже как в общем это организовать?

    сделать два TFDMemTable (источника и приемника) ? какими методами внутри пользоваться, edit/append/delete или sql запросами, что быстрее?

    применять ли мне кэширование и tfdmemTable одновременно ?

    Вопрос: как правильно и БЫСТРО обработать большой объем данных?

    П.С. может дадите хорошую ссылку на статью, где описан принцип построения приложения, или классный исходник, где можно было бы подсмотреть как делают профессионалы (желательно с минимумом обращения к визуальным компонентам вообще, т.к. моё приложение я буду переделывать в консольное, для фоновой обработки). В будущем мне кстати понадобятся ещё потоки для одновременной обработки нескольких таких таблиц, есть ли готовые компоненты в firedac или пользоваться tthread, масса вопросов....

  3. Скажите, появились ли  за последние 3 года в fireminkey библиотеки, работающие с ком портом и из винды и линукс?

    нужно из windows и linux работать с ком портами на разной скорости, а также выставлять/читать пины кроме tx/rx, такие как ri, cts, dcd и т.п.

     

×
×
  • Создать...