-
Доброго времени суток! Написал следующее:
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ой записи программа вываливается с ошибкой о нехватке памяти. Куда девается память? Что я делаю неправильно?
-
> SelectSQL.Text := 'INSERT
Ты , наверно, заболел ?)
-
При чем, серьёзно заболел...
-
а не проще ли завести параметры, чем каждый раз строку записывать?
-
> clickmaker © (06.10.08 17:31) [3]
А смысл?После заполнения ВСЕХ сиквелов, IBDataSet ведет себя как обычный DataSet: Insert/Post/Edit/Delete
-
> clickmaker © (06.10.08 17:31) [3] > а не проще ли завести параметры, чем каждый раз строку записывать?
Более того - именно параметрические запросы и должны быть у данного компонента!
-
> А смысл?
в некоторых случаях сиквел составит более оптимальный план запроса. В данном случае, правда, это не очень актуально.
-
> for j := 0 to Res.Count-1 do begin ... > ServerFT.Transaction.Commit;
50 тыс коммитов? ну-ну
-
А этот код работает? Предлагаю для начала переписать его хотя бы в таком виде: 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;
-
> хотя бы в таком виде: предлагаю добавить/заменить > ExecQuery;
> end;
> Transaction.Commit; на ...
ExecQuery;
if j mod 5000 = 0 then begin
Transaction.Commit;
Transaction.StartTransaction;
end;
end;
if Transaction.InTransaction then
Transaction.Commit;
...
-
Не вижу великого смысла в подтверждении КАЖДОЙ вставки. Ну а кроме этого, зачем всякий раз завершать транзакцию и затем неявно вновь ее стартовать ?
-
И вообще. В подобных случаях (большие объемы вставок-модификаций, фрмируемые на клиенте) лучше все-таки следовать "пакетной" технологии:
- Создается временная таблица на сервере - Туда заносятся все записи пакета - Запускается от 1 до 3 запросов на вставку, удаление, изменение.
Результат: а) Сервер не "напрягается" на длительное время обслуживанием одного клиента и не "блокирует" таблицы (в смысле не держит длительное время версии кучи записей) б) Удобно управлять транзакциями, не "карауля" каждый пук с клиента, а ловя сбой лишь в момент ошибки, если она возникает в) Просто намного прозрачнее с т.зр.логики приложения
>kaif © (06.10.08 18:16) [8]
Настоящие пачаны на обработку ошибки не заморачиваются ?
-
> MsGuns © (06.10.08 21:02) [10] > Не вижу великого смысла в подтверждении КАЖДОЙ вставки.
Не каждая, а каждые 5000. В соответствии с рекомендациями лучших ИБ/ФБ'водов надо каждые ~500. Что и есть "пакет". Без неуместной вр.таблицы. Остальные "результаты" а) б) в) как минимум странны...
-
можно дураку объяснить - какой смысл в commit-е порциями (ну скажем, по 500-1000 штук) ?
-
>Johnmen © (06.10.08 21:28) [12] >Не каждая, а каждые 5000. В соответствии с рекомендациями лучших >ИБ/ФБ'водов надо каждые ~500.
>Игорь Шевченко © (06.10.08 22:19) [13] >можно дураку объяснить - какой смысл в commit-е порциями (ну скажем, >по 500-1000 штук) ?
И мне заодно тоже
-
Попробовал выше описаный вариант
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 записи память кончается :)
-
> DelphiN! (07.10.08 06:28) [15]
Укажи конкретную строчку кода из [15], при выполнении которой возбуждается исключение. Приведи дословно текст сообщения об исключении.
-
Еще раз (настойчиво):
зачем всякий раз завершать транзакцию и затем вновь ее стартовать ?
И еще вопрос - сервер где запущен - на твоем компе ?
-
> DelphiN! (07.10.08 06:28) [15]
Может, IBX надо проапдейтить?
-
> можно дураку объяснить - какой смысл в commit-е порциями > (ну скажем, по 500-1000 штук) ?
быстрее вставка происходить будет.
|