Конференция "Базы" » Утечка памяти при работе с TIbDataSet [D6, FireBird 2.1]
 
  • DelphiN! (06.10.08 16:09) [0]
    Доброго времени суток!
    Написал следующее:

         for j := 0 to Res.Count-1 do
         begin
           ServerFT.SelectSQL.Text := 'INSERT INTO SERVERFT (FILENAME,FILESIZE,FILECRC,BASEDIR) VALUES('''+Res.FileName[j]+''','+
             IntToStr(Res.FileSize[j])+','+IntToStr(Res.FileCRC[j])+', '''+Res.BaseDir[j]+''')';
           ServerFT.ExecSQL;
           ServerFT.Transaction.Commit;
         end;



    В массиве Res более 50 000 записей, при дохождении цикла до 5080ой записи программа вываливается с ошибкой о нехватке памяти. Куда девается память? Что я делаю неправильно?
  • Сергей М. © (06.10.08 16:51) [1]

    > SelectSQL.Text := 'INSERT


    Ты , наверно, заболел ?)
  • Виталий Панасенко (06.10.08 17:16) [2]
    При чем, серьёзно заболел...
  • clickmaker © (06.10.08 17:31) [3]
    а не проще ли завести параметры, чем каждый раз строку записывать?
  • Виталий Панасенко (06.10.08 17:43) [4]

    > clickmaker ©   (06.10.08 17:31) [3]

    А смысл?После заполнения ВСЕХ сиквелов, IBDataSet ведет себя как обычный DataSet: Insert/Post/Edit/Delete
  • Johnmen © (06.10.08 17:47) [5]

    > clickmaker ©   (06.10.08 17:31) [3]
    > а не проще ли завести параметры, чем каждый раз строку записывать?

    Более того - именно параметрические запросы и должны быть у данного компонента!
  • clickmaker © (06.10.08 17:48) [6]
    > А смысл?

    в некоторых случаях сиквел составит более оптимальный план запроса.
    В данном случае, правда, это не очень актуально.
  • Правильный$Вася (06.10.08 18:02) [7]

    > for j := 0 to Res.Count-1 do      begin ...
    >    ServerFT.Transaction.Commit;

    50 тыс коммитов? ну-ну
  • kaif © (06.10.08 18:16) [8]
    А этот код работает?
    Предлагаю для начала переписать его хотя бы в таком виде:

    with TIBSQL.Create(nil) do
    try
     Transaction := <компонент транзакции>;

     if not Transaction.InTransaction then
       Transaction.StartTransaction;

     SQL.Text := 'INSERT INTO SERVERFT (FILENAME,FILESIZE,FILECRC,BASEDIR)
       VALUES(:FILENAME,:FILESIZE,:FILECRC,:BASEDIR)'
    ;

     for j := 0 to Res.Count-1 do
     begin
          Params[0].AsString := Res.Filename[j];
          Params[1].AsInteger := Res.Res.FileSize[j];
          Params[2].AsInteger := Res.FileCRC[j];
          Params[3].AsString := Res.BaseDir[j];
          ExecQuery;
     end;

     Transaction.Commit;
    finally
     Free;
    end;

  • sniknik © (06.10.08 19:55) [9]
    > хотя бы в таком виде:
    предлагаю добавить/заменить
    >     ExecQuery;
    > end;

    > Transaction.Commit;


    на
    ...
          ExecQuery;
          if j mod 5000 = 0 then begin
            Transaction.Commit;
            Transaction.StartTransaction;
          end;
     end;

     if Transaction.InTransaction then
       Transaction.Commit;
    ...

  • MsGuns © (06.10.08 21:02) [10]
    Не вижу великого смысла в подтверждении КАЖДОЙ вставки.
    Ну а кроме этого, зачем всякий раз завершать транзакцию и затем неявно вновь ее стартовать ?
  • MsGuns © (06.10.08 21:10) [11]
    И вообще.
    В подобных случаях (большие объемы вставок-модификаций, фрмируемые на клиенте) лучше все-таки следовать "пакетной" технологии:

    - Создается временная таблица на сервере
    - Туда заносятся все записи пакета
    - Запускается от 1 до 3 запросов на вставку, удаление, изменение.

    Результат:
    а) Сервер не "напрягается" на длительное время обслуживанием одного клиента и не "блокирует" таблицы (в смысле не держит длительное время версии кучи записей)
    б) Удобно управлять транзакциями, не "карауля" каждый пук с клиента, а ловя сбой лишь в момент ошибки, если она возникает
    в) Просто намного прозрачнее с т.зр.логики приложения

    >kaif ©   (06.10.08 18:16) [8]

    Настоящие пачаны на обработку ошибки не заморачиваются ?
  • Johnmen © (06.10.08 21:28) [12]

    > MsGuns ©   (06.10.08 21:02) [10]
    > Не вижу великого смысла в подтверждении КАЖДОЙ вставки.

    Не каждая, а каждые 5000. В соответствии с рекомендациями лучших ИБ/ФБ'водов надо каждые ~500. Что и есть "пакет". Без неуместной вр.таблицы.
    Остальные "результаты" а) б) в) как минимум странны...
  • Игорь Шевченко © (06.10.08 22:19) [13]
    можно дураку объяснить - какой смысл в commit-е порциями (ну скажем, по 500-1000 штук) ?
  • MsGuns © (07.10.08 00:50) [14]
    >Johnmen ©   (06.10.08 21:28) [12]
    >Не каждая, а каждые 5000. В соответствии с рекомендациями лучших >ИБ/ФБ'водов надо каждые ~500.

    >Игорь Шевченко ©   (06.10.08 22:19) [13]
    >можно дураку объяснить - какой смысл в commit-е порциями (ну скажем, >по 500-1000 штук) ?

    И мне заодно тоже
  • DelphiN! (07.10.08 06:28) [15]
    Попробовал выше описаный вариант

         with TIBSQL.Create(nil) do
         try
           Transaction := IBDatabase1.DefaultTransaction;

           if not Transaction.InTransaction then
             Transaction.StartTransaction;

           SQL.Text := 'INSERT INTO SERVERFT (FILENAME,FILESIZE,FILECRC,BASEDIR) '+
             'VALUES(:FILENAME,:FILESIZE,:FILECRC,:BASEDIR)';

           for j := 0 to Res.Count-1 do
           begin
             labState.Caption := 'Статус : Обновление файловой таблицы сервера [Импорт файлов('+IntToStr(j)+'/'+IntToStr(Res.Count)+')] ... ';
             Application.ProcessMessages;
             Params[0].AsString := Res.Filename[j];
             Params[1].AsInteger := Res.FileSize[j];
             Params[2].AsInteger := Res.FileCRC[j];
             Params[3].AsString := Res.BaseDir[j];
             ExecQuery;
             if j mod 5000 = 0 then
             begin
               Transaction.Commit;
               Transaction.StartTransaction;
             end;
           end;

           if Transaction.InTransaction then
             Transaction.Commit;
         finally
           Free;
         end;
       end;


    Всеравно утечка, только уже на 35011 записи память кончается :)
  • Сергей М. © (07.10.08 08:31) [16]

    > DelphiN!   (07.10.08 06:28) [15]


    Укажи конкретную строчку кода из [15], при выполнении которой возбуждается исключение.
    Приведи дословно текст сообщения об исключении.
  • MsGuns © (07.10.08 09:14) [17]
    Еще раз (настойчиво):

    зачем всякий раз завершать транзакцию и затем вновь ее стартовать ?

    И еще вопрос - сервер где запущен - на твоем компе ?
  • Виталий Панасенко (07.10.08 09:27) [18]

    > DelphiN!   (07.10.08 06:28) [15]

    Может, IBX надо проапдейтить?
  • jack128_ (07.10.08 10:12) [19]

    > можно дураку объяснить - какой смысл в commit-е порциями
    > (ну скажем, по 500-1000 штук) ?

    быстрее вставка происходить будет.
 
Конференция "Базы" » Утечка памяти при работе с TIbDataSet [D6, FireBird 2.1]
Есть новые Нет новых   [134474   +34][b:0][p:0.003]