Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2009.07.05;
Скачать: [xml.tar.bz2];

Вниз

Утечка памяти при работе с TIbDataSet   Найти похожие ветки 

 
DelphiN!   (2008-10-06 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ой записи программа вываливается с ошибкой о нехватке памяти. Куда девается память? Что я делаю неправильно?


 
Сергей М. ©   (2008-10-06 16:51) [1]


> SelectSQL.Text := "INSERT


Ты , наверно, заболел ?)


 
Виталий Панасенко   (2008-10-06 17:16) [2]

При чем, серьёзно заболел...


 
clickmaker ©   (2008-10-06 17:31) [3]

а не проще ли завести параметры, чем каждый раз строку записывать?


 
Виталий Панасенко   (2008-10-06 17:43) [4]


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

А смысл?После заполнения ВСЕХ сиквелов, IBDataSet ведет себя как обычный DataSet: Insert/Post/Edit/Delete


 
Johnmen ©   (2008-10-06 17:47) [5]


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

Более того - именно параметрические запросы и должны быть у данного компонента!


 
clickmaker ©   (2008-10-06 17:48) [6]

> А смысл?

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


 
Правильный$Вася   (2008-10-06 18:02) [7]


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

50 тыс коммитов? ну-ну


 
kaif ©   (2008-10-06 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 ©   (2008-10-06 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 ©   (2008-10-06 21:02) [10]

Не вижу великого смысла в подтверждении КАЖДОЙ вставки.
Ну а кроме этого, зачем всякий раз завершать транзакцию и затем неявно вновь ее стартовать ?


 
MsGuns ©   (2008-10-06 21:10) [11]

И вообще.
В подобных случаях (большие объемы вставок-модификаций, фрмируемые на клиенте) лучше все-таки следовать "пакетной" технологии:

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

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

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

Настоящие пачаны на обработку ошибки не заморачиваются ?


 
Johnmen ©   (2008-10-06 21:28) [12]


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

Не каждая, а каждые 5000. В соответствии с рекомендациями лучших ИБ/ФБ"водов надо каждые ~500. Что и есть "пакет". Без неуместной вр.таблицы.
Остальные "результаты" а) б) в) как минимум странны...


 
Игорь Шевченко ©   (2008-10-06 22:19) [13]

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


 
MsGuns ©   (2008-10-07 00:50) [14]

>Johnmen ©   (06.10.08 21:28) [12]
>Не каждая, а каждые 5000. В соответствии с рекомендациями лучших >ИБ/ФБ"водов надо каждые ~500.

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

И мне заодно тоже


 
DelphiN!   (2008-10-07 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 записи память кончается :)


 
Сергей М. ©   (2008-10-07 08:31) [16]


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


Укажи конкретную строчку кода из [15], при выполнении которой возбуждается исключение.
Приведи дословно текст сообщения об исключении.


 
MsGuns ©   (2008-10-07 09:14) [17]

Еще раз (настойчиво):

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

И еще вопрос - сервер где запущен - на твоем компе ?


 
Виталий Панасенко   (2008-10-07 09:27) [18]


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

Может, IBX надо проапдейтить?


 
jack128_   (2008-10-07 10:12) [19]


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

быстрее вставка происходить будет.


 
MsGuns ©   (2008-10-07 10:26) [20]

>jack128_   (07.10.08 10:12) [19
>быстрее вставка происходить будет.

и фиг с ней, с целостностью ?


 
Johnmen ©   (2008-10-07 10:27) [21]


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

Смысл - не накапливать версии записей, ускорение. Почитать, как обычно, можно на ibase.ru

> MsGuns ©   (07.10.08 00:50) [14]
> И мне заодно тоже

В чем сомнения?

> DelphiN!

Рекомендуется к прочтению http://www.ibase.ru/devinfo/ibx.htm


 
jack128_   (2008-10-07 10:50) [22]


> и фиг с ней, с целостностью ?

а ты уверен, что вставка 500 записей нарушит целостность?


 
Игорь Шевченко ©   (2008-10-07 10:53) [23]

Johnmen ©   (07.10.08 10:27) [21]


> Смысл - не накапливать версии записей, ускорение. Почитать,
>  как обычно, можно на ibase.ru


Тогда чем плохо коммитить по одной ? Вопрос был о том, зачем именно пакет организовывать


 
DelphiN!   (2008-10-07 14:33) [24]

Проблему решил обновлением компонентов IBX. Стояла старая, глючная версия ..
Всем большое спасибо за помощь!


 
MsGuns ©   (2008-10-07 16:20) [25]

>jack128_   (07.10.08 10:50) [22]
>а ты уверен, что вставка 500 записей нарушит целостность?

А ты уверен, что НЕ нарушит ?

А вообще корень проблемы раскрыт в [23]


 
DrPass ©   (2008-10-07 16:41) [26]


> Игорь Шевченко ©   (07.10.08 10:53) [23]
> Johnmen ©   (07.10.08 10:27) [21]
>
> Тогда чем плохо коммитить по одной ? Вопрос был о том, зачем
> именно пакет организовывать

Потому что коммит после каждой записи также заметно замедляет работу. Оптимальный по производительности способ вставки больших массивов в IB - именно пакетами (количество записей в пакете зависит от многих параметров)


 
Игорь Шевченко ©   (2008-10-07 16:44) [27]

DrPass ©   (07.10.08 16:41) [26]


> Потому что коммит после каждой записи также заметно замедляет
> работу. Оптимальный по производительности способ вставки
> больших массивов в IB - именно пакетами (количество записей
> в пакете зависит от многих параметров)


ну понятно - black voodoo. Желающие подкручивать гайки без хлеба не останутся. Но все-таки - насколько мне известно, IB не запускает сборку мусора после каждого commit, версии все равно зависят от количества одновременно стартовавших транзакций - какая физика механизма, что при транзакции "пакетом" быстродействие выше ? Если не затруднит, то ссылочку с ibase.ru


 
DrPass ©   (2008-10-07 17:28) [28]


> IB не запускает сборку мусора после каждого commit,

Причем здесь вообще сборка мусора, если речь идет о вставке (а не удалении, обновлении и выборке) записей?
Игорь, скажите, что эффективнее будет работать - пятьсот раз переписать страницу данных и один раз - страницу состояний транзакций в конце всего этого, или пятьсот раз переписать страницу данных и пятьсот раз страницу состояний транзацкий после каждой вставки? Имейте в виду, сервер IB обычно работает в режиме прямой записи на диск, без кеширования!
Никакой черной магии, элементарная логика, подтвержденная опытом работы с сервером. Я понимаю, вы любитель поумничать. Но зачем умничать в тех областях, в которых вы слабо разбираетесь-то?


 
MsGuns ©   (2008-10-07 17:32) [29]

> количество записей в пакете зависит от многих параметров

Ерунда, это зависит только от дурости программиста.
При работе с многострочным документом используется статус документа, коммитится же КАЖДАЯ введенная (исправленная) запись,
при всевозможных "заливках" ничего лучше раскритикованного джонменом способа с временной таблицей нет
во всех остальных случаях вполне достаточно "чистого" сиквеля

Все остальное - от лукавого


 
Правильный$Вася   (2008-10-07 17:34) [30]


>  сервер IB обычно работает в режиме прямой записи на диск,
>  без кеширования!

да ну
по умолчанию как раз наоборот
а вот если принудительно выставить ForceWrite, тогда да, это это для параноиков и на особо ответственных базах
но массовая загрузка данных всегда отличалась от обычной работы, причем независимо от субд


 
Правильный$Вася   (2008-10-07 17:36) [31]


> MsGuns ©   (07.10.08 17:32) [29]

холиваров не надо, каждый свое мнение может иметь, основанное на опыте


 
MsGuns ©   (2008-10-07 17:39) [32]

>DrPass ©   (07.10.08 17:28) [28]
>Никакой черной магии, элементарная логика, подтвержденная опытом работы с сервером. Я >понимаю, вы любитель поумничать. Но зачем умничать в тех областях, в которых вы слабо >разбираетесь-то?

Давай без зеленых человечеков и словокатанием в духе "бывают случаи"
Приведи практический пример, в котором приведенных в [29] вариантов не хватает для решения задачи. Только не надо мне рассказывать, что сервер на временную таблицу с последующим ЕДИНСТВЕННЫМ insert to ОСНОВНАЯ ТАБЛИЦА from select будет заморачиваться круче, чем "держать" версии стотыщмильонов записей, агрументируя аргументов, что он де работает без кеширования (причем тут это вообще непонятно)

А то мы так до третьих петухов будем "умничать"


 
Игорь Шевченко ©   (2008-10-07 17:49) [33]

DrPass ©   (07.10.08 17:28) [28]


> Никакой черной магии, элементарная логика, подтвержденная
> опытом работы с сервером. Я понимаю, вы любитель поумничать.
>  Но зачем умничать в тех областях, в которых вы слабо разбираетесь-
> то?


То есть, ссылочки на ibase.ru не будет, я верно понимаю ?


 
kaif ©   (2008-10-07 18:13) [34]

2 MsGuns ©  

Временные таблицы - это стиль MSSQL,  а не IB.

Насчет оптималности подтверждения после каждых 5тыс. мог бы поспорить, так как конркетно для IB все равно, коммитить после каждых 5000 или после каждых 50 тыс. Почему, например, не после каждых 500?

Насчет обработки ошибок согласен, я не показал этого в коде. Сознательно посчитал это излишним. Как, впрочем, и коммит после каждых 5000. Так как правильная обработка ошибок от задачи зависит. Например, человека может быть устроит вообще наглухо подавить все ошибки, нарушения уникального ключа (unique key violation) и при этом одновременно ни в коем случае не подавлять ошибки, связанные с обрезанием строки (в данном случае у него имя файла) по длине (string truncation). А так как у него (как он сам сказал) всего 50 тыс записей, я и посчитал излишним и подтверждение после "каждых стольких-то". Так как 50 тыс для IB - цифра, допускающая откатить всю вставку, а логика обработки ошибок в его случае может требовать такого отката (например, если в условии задачи - не потерять ни один файл при импорте, если что-то не так - отменить весь импорт, откатив транзакцию, разобраться и попробовать импорт вновь).

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

Оптимальный и легко в дальнейшем развиваемый код я бы оформил так:

var
 FilenameParam,
 FielSizeParam,
 FileCRCParam,
 BaseDirParam : TParam;

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)";

FilenameParam := ParamByName("FILENAME");
FielSizeParam := ParamByName("FILESIZE);
FileCRCParam := ParamByName("FILECRC");
BaseDirParam := ParamByName("BASEDIR");

for j := 0 to Res.Count-1 do
begin
     FilenameParam.AsString := Res.Filename[j];
     FielSizeParam.AsInteger := Res.Res.FileSize[j];
     FileCRCParam.AsInteger := Res.FileCRC[j];
     BaseDirParam.AsString := Res.BaseDir[j];
     ExecQuery;

  и т.д.
 


 
DrPass ©   (2008-10-07 18:26) [35]


> kaif ©   (07.10.08 18:13) [34]


> Насчет оптималности подтверждения после каждых 5тыс. мог
> бы поспорить, так как конркетно для IB все равно, коммитить
> после каждых 5000 или после каждых 50 тыс. Почему, например,
>  не после каждых 500?

Никто и не говорит про 5 тыс. Вполне вероятно, что лучшим будет вариант одного-единственного коммита в конце всего пакета. Лишь бы не после каждой записи


> MsGuns ©   (07.10.08 17:39) [32]


> Приведи практический пример, в котором приведенных в [29]
> вариантов не хватает для решения задачи

Мы говорим о "возможности решения задачи" или об ее оптимальном решении? Чтобы просто вставлять записи в БД можно вообще не заморачиваться. Тем более что предложенные варианты никаких преимуществ не имеют. Например, по поводу редактирования многострочного документа коммит каждой строки вообще неудобная крайность. Временные таблицы - тоже неправильный подход. Если надо просто залить данные в плоскую таблицу - зачем делать промежуточное хранилище? Что мы этим выиграем?

> Игорь Шевченко ©   (07.10.08 17:49) [33]


> То есть, ссылочки на ibase.ru не будет, я верно понимаю
> ?

Не будет. А вы очевидных решений без ссылочек не принимаете? Жаль. На все случаи в жизни ссылочек не напасешься...


 
Игорь Шевченко ©   (2008-10-07 18:37) [36]

DrPass ©   (07.10.08 18:26) [35]


> Не будет.


Тогда нефиг "
> Я понимаю, вы любитель поумничать. Но зачем умничать в тех
> областях, в которых вы слабо разбираетесь-то?

"

в IB я чуть-чуть разбираюсь. Это так, к слову


 
Правильный$Вася   (2008-10-07 18:50) [37]


> То есть, ссылочки на ibase.ru не будет, я верно понимаю

http://www.ibase.ru/devinfo/dontdoit.htm
пункты 7 и 8


 
DrPass ©   (2008-10-07 19:01) [38]


> Игорь Шевченко ©   (07.10.08 18:37) [36]
> DrPass ©   (07.10.08 18:26) [35]
>
> Тогда нефиг "
>
> в IB я чуть-чуть разбираюсь. Это так, к слову

Очень хорошо. Практика - критерий истины. Согласны? Сделайте так:
1. Табличку в базе (у меня FB 2.1, но думаю, это не принципиально)
create table test(a int, b int)

2. Простенькое приложение - две кнопки, мемо, ibdatabase, ibtransaction, ibsql
Запрос такой:
insert into test(a, b) values (:a, :b)

3. Ну и соответственно код:
procedure TForm1.Button1Click(Sender: TObject);
var
 i: integer;
 a, b: cardinal;
begin
 a:= GetTickCount;
 IBTransaction1.StartTransaction;
 for i := 0 to 10000 - 1 do
 begin
   IBSQL1.ParamByName("a").Value:= random(1000);
   IBSQL1.ParamByName("b").Value:= random(1000);
   IBSQL1.ExecQuery;
 end;
 IBTransaction1.Commit;
 b:= GetTickCount;
 Memo1.Lines.Add(inttostr(b - a));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
 i: integer;
 a, b: cardinal;
begin
 a:= GetTickCount;
 for i := 0 to 10000 - 1 do
 begin
   IBTransaction1.StartTransaction;
   IBSQL1.ParamByName("a").Value:= random(1000);
   IBSQL1.ParamByName("b").Value:= random(1000);
   IBSQL1.ExecQuery;
   IBTransaction1.Commit;
 end;
 b:= GetTickCount;
 Memo1.Lines.Add(inttostr(b - a));
end;


У меня в первом случае (запускал по пять раз):
422
453
438
422
421

Во втором:
9719
9797
9641
9891
10171

Как по-вашему, есть разница - делать коммит после каждой записи, или нет?


 
Johnmen ©   (2008-10-07 20:02) [39]


> DrPass ©   (07.10.08 19:01) [38]

Да не надо ему ничего объяснять. Если бы ему действительно было интересно, он бы давно набрал "массовая вставка" в поиске на ibase.ru и изучил бы тему...
А на самом деле Игорь занимается любимым делом - занудством :)
Конечно же позанудствовать можно и даже бывает нужно. Но чувство меры не должно отказывать...


 
Игорь Шевченко ©   (2008-10-07 20:03) [40]

DrPass ©   (07.10.08 19:01) [38]


> Очень хорошо. Практика - критерий истины. Согласны?


Нет, не согласен. Критерий истинности - всегда задача. Я не зря спросил именно про искусственное разделение всего объема на порции по N операторов. Допустим, у меня есть задача вставить, скажем, 20000 записей.
В зависимости от того, что надо сделать, если 15732-ая не вставилась, я и буду строить логику - если требуется откатить все изменения, то и транзакция будет одна.

Правильный$Вася   (07.10.08 18:50) [37]

Ну так по сылке говорят "не делайте". А почему - не говорят. Меня интересовала ссылка на "почему". Например, тот же Кайт, рассказывая про оракл, честно говорит, почему невыгодно при массовых операциях делать commit после каждого оператора. Но точно также и говорит, что искусственно разбивать большое обновление на кучу мелких транзакций еще более невыгодно.


 
MsGuns ©   (2008-10-07 20:22) [41]

>Правильный$Вася   (07.10.08 18:50) [37]
>http://www.ibase.ru/devinfo/dontdoit.htm
>пункты 7 и 8

>7. Не надо делать коммит после каждой записи, если это не требуется по >смыслу

Абсолютно справедливо. Однако о каком "смысле" идет речь при настырном трындеже "лучше резать по кусочкам, чем сразу в мясорубку" ?

>8. Не надо делать commit после вставки каждой записи, если вы их >вставляете больше 10 за один раз

Никто и не спорит. Только опять же кто, где и когда скажет о сабже, в какой момент и поскольку надо вставлять за раз ?

"За что ж аборигены съели Кука ? О том ни слова. Молчит наука" (с)


 
MsGuns ©   (2008-10-07 20:29) [42]

>kaif ©   (07.10.08 18:13) [34]
>Временные таблицы - это стиль MSSQL,  а не IB.

Ашот, не надо метром мерять объемы, а ? Есть задача и надо найти для ее решения оптимальный способ. А в "стиле" это или нет - это уже эстетство, в данном случае к делу никакого отношения не имеющее.

>Johnmen ©   (07.10.08 20:02) [39]
>А на самом деле Игорь занимается любимым делом - занудством :)
>Конечно же позанудствовать можно и даже бывает нужно. Но чувство меры >не должно отказывать...

Ну наконец-то. Дождались. Когда мысли закончились, в ход пошел высунутый язык и рожки.


 
Сергей М. ©   (2008-10-07 20:35) [43]

А автор тем временем засох)..

Или сбежал - страшно стало от затеянного ..

Ни ответа от него , ни привета ..


 
DrPass ©   (2008-10-07 20:38) [44]


> Игорь Шевченко ©   (07.10.08 20:03) [40]


> Допустим, у меня есть задача вставить, скажем, 20000 записей.
>
> В зависимости от того, что надо сделать, если 15732-ая не
> вставилась, я и буду строить логику - если требуется откатить
> все изменения, то и транзакция будет одна.

Игорь, это само собой разумеется. Но нас этот вопрос вообще не должен интересовать, т.к. логика обработки ошибок - дело сугубо индивидуальное, тут миллионы вариантов, и обсуждать их без конкретной постановки задачи нет никакого смысла. Мы вообще-то говорили о производительности вставки записей в общем случае, без изысков и дополнительных условий.
Да и вы вообще-то не так давно совсем в другую сторону вели (вот тут я не ссылочку, а цитатку приведу, не возражаете?)

> ну понятно - black voodoo. Желающие подкручивать гайки без
> хлеба не останутся. Но все-таки - насколько мне известно,
>  IB не запускает сборку мусора после каждого commit, версии
> все равно зависят от количества одновременно стартовавших
> транзакций - какая физика механизма, что при транзакции
> "пакетом" быстродействие выше ?

А вы теперь перед очевидными доказательствами сразу решили в кусты слинять, что-то там про конкретные задачи? ;-)


 
DrPass ©   (2008-10-07 20:38) [45]


> Сергей М. ©   (07.10.08 20:35) [43]
> А автор тем временем засох)..

А зачем он нам? Мы и без него неплохо пообщаемся :-D


 
Игорь Шевченко ©   (2008-10-07 20:52) [46]

DrPass ©   (07.10.08 20:38) [44]


> А вы теперь перед очевидными доказательствами сразу решили
> в кусты слинять, что-то там про конкретные задачи? ;-)


Ну так физики-то так и нету ? А практических примеров я тоже могу. Давай продолжим дискуссию с поста [13]


 
Германн ©   (2008-10-07 21:28) [47]


> Ну так физики-то так и нету ?

Какая физика? Сегодня вся физика в Стокгольме была :)


 
kaif ©   (2008-10-07 22:10) [48]

MsGuns ©   (07.10.08 20:29) [42]
>kaif ©   (07.10.08 18:13) [34]
>Временные таблицы - это стиль MSSQL,  а не IB.

Ашот, не надо метром мерять объемы, а ? Есть задача и надо найти для ее решения оптимальный способ. А в "стиле" это или нет - это уже эстетство, в данном случае к делу никакого отношения не имеющее.


Сергей, ты неправ. Оптимальное решение в MSSQL и в IB могут оказаться просто прямо противоположными.

Так как IB версионник, а MSSQL - блокировочник.
В MSSQL временные таблицы используются повсеместно, возможно, как лучший способ избежать эскалации блокировок. Временные таблицы можно  даже создавать в хранимых процедурах, а в IB так действовать не принято. Я даже не уверен, что в IB можно использовать CREATE TABLE  в ХП (может в каких-то поздних версиях можно, я не в курсе, так как никогда этим не пользуюсь).

Поэтому и решения для этих двух серверов в данном случае могут быть разными. Я лично в IB никогда не пользуюсь временными таблицами.

И я против таких подходов в IB.
Объясню почему.

При импорте данных наиважнейшими обстоятельствами являются:

1. ссылочная целостность данных
2. скорость.

Временная таблица никаких преимуществ в версионниках в смысле блокировок не дает,  так как никаких блокировок в версионниках попросту не бывает, а при INSERT даже Lock-конфликтов (конкуренции за апдейт одной записи) не предвидится. Так что временная таблица для импорта в версионнике - полный маразм, перестраховщина и излишество.

А вот создавать временную таблицу и вешать на нее foreign key есть еще больший маразм, так как это потребует кучи дополнительных ресурсов и еще больше замедлит импорт.
А если не вешать foreign key, то я не знаю, как обеспечить ссылочную целостность при импорте.
В MSSQL многие вообще не используют foreign key, а проверки делают в триггерах. Старые версии MSSQL (может я ошибаюсь) про декларативную ссылочность вообще ничего не знали, а некоторые учебники до сих пор не рекомендуют ее юзать, предпочитая делать все в триггерах.
А в IB всегда все было прямо наоборот. Декларативной ссылочной целостности уделялось много внимания, а в триггерах заниматься этими проверками в IB просто не рекомендуется по ряду причин. И первая из них - триггер работает в контексте транзакции, а внешний ключ - вне контекста транзакции. Поэтому в IB триггер не обеспечивает со 100% вероятностью ссылочной целостности, а внешний ключ - обеспечивает.

Плюсов же во временной таблице я никаких не вижу вообще.

Я писал десятки программ, в которых приходилось делать импорт в IB,  в некоторых до миллиона записей. Ни разу временные таблицы я не применял и применять (в IB конкретно) не собираюсь.


 
Johnmen ©   (2008-10-07 22:29) [49]


> kaif ©   (07.10.08 22:10) [48]

Да-да.
В IB до 7.5 и в FB до 2.0, как минимум, не было "встроенных" таблиц. Выполнять DDL команды (в т.ч. CREATE TABLE) в SP недопустимо. Менять структуру БД, создавая таблицу, например, "в рантайме" категорически не рекомендовано. Особенно при незнании определенных нюансов и особенностей.


 
MsGuns ©   (2008-10-07 22:38) [50]

Охохохохонюшки..
Я ему при пльзеньское, он мне про златолюбие блондинок.

Причем здесь вообще форин, а ? Ну какая разница, каким макаром всталять записи в таблицу - хором (запросом Insrt to select from) или поодиночке с точки зрения ссылочной целостности, а ?

Далее. Про "полный маразм, перестраховщину и излишество", т.е. временные таблицы.

...

Фух, начал писАть примеры, наваял два экрана и плюнул ;(
Ну почему тебе надо объяснять очевидное - что лучше во временной таблице, к которой даже теоретически не может быть попыток доступа из других коннектов, собрать все добавляемые записи, а после этого запустить ОДИН запрос и при этом ВСЕ ДАННЫЕ сервер будет брать непосредственно "в себе", не дожидаясь завершения всякой внешней фигни типа тормозов сетки/клиента и т.д. И если что-то не получится, то откатит всю транзакцию. Понимаешь - ВСЮ ! Т.е. все стотыщмильонов записей. А не "аварийную" порцию в твоем "хирургически-традиционном" методе. Во-первых, представлю, как сервер собирает и ХРАНИТ ДЛИТЕЛЬНОЕ ВРЕМЯ (особенно если клиент "медленный") 49999 версий записей и только при добавлении 50000-й "спускает пар", затем вся эта хрень повторятся для следующей порции и т.д.
Но самое смешное, если при отсылке 999-й порции выяснится, что очередная запись не может быть внесена в БД (хотя бы по причине  нарушения так любимой тобою ссылочной целостности) и поэтому ВСЮ ВСТАВКУ НАДО ОТМЕНИТЬ. Вот что ты предлагаешь в этом случае ? Поднимать бэкап и петь "осанну" "классической" хирургии, принесшей в жертву науки только что склеившего ласты при операции аппендицита несчасного пациента ? И ховаться в жито от разгневанных родных и близких зарезанного ?


 
MsGuns ©   (2008-10-07 22:42) [51]

>Johnmen ©   (07.10.08 22:29) [49]

Замечательно. Конечно, сабж - это, конечно, нетипичный случай. Но если возникает все же такая необходимость - заливать объемные данные извне - что делать ? Ваш способ нафиг и я объяснил почему.
ИБ у меня попал в разряд "немилостевых" и потому в том числе, что разработчики не удосужились придумать хотя бы что-то напоминающее мелкософтовый DTS


 
MsGuns ©   (2008-10-07 22:47) [52]

>Johnmen ©  

ИШ, конечно, зануда, я понимаю.
Я - зловредный и ехидный тип, никого, окромя себя не видящий и не слышащий.
А вместе мы дилетанты.

Но что ты скажешь, если и тебе приклеить ярлычок - "догматик" ?


 
Johnmen ©   (2008-10-07 22:50) [53]

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

>быстрее вставка происходить будет.

>MsGuns ©   (07.10.08 10:26) [20]
>и фиг с ней, с целостностью ?

и вдруг
>MsGuns ©   (07.10.08 22:38) [50]
>Ну какая разница, каким макаром всталять записи в таблицу - хором
>(запросом Insrt to select from) или поодиночке с точки зрения ссылочной
>целостности, а ?

Ты, Серега, что-то совсем заговорился...
Далее читать посты глубоко верующего в единственность и непогрешимость просто неинтересно.
Хотя, возможно, ты говоришь про что-то своё, не связанное с темой ветки. Тогда - просто бесполезно.


 
MsGuns ©   (2008-10-07 22:50) [54]

Поймите же в конце концов, что при вашей "хирургии" ДЛИТЕЛЬНЫЕ ПИШУЩИЕ ТРАНЗАКЦИИ, против коих так дружно вопят все классики интербизма-файрбердизма, просто неизбежны !


 
MsGuns ©   (2008-10-07 22:53) [55]

>Johnmen ©   (07.10.08 22:50) [53]

Под "целостностью" я в данном случае (первая цитата) имел в виду не нарушение форинкеев, а нечто другое - когда в БД попадут НЕ ВСЕ записи, а только часть, причем абсолютно неизвестно заранее какая. Что прикажете делать админу БД в этом случае ?

Слушаю с замиранием сердца ;)


 
Johnmen ©   (2008-10-07 22:54) [56]


> MsGuns ©   (07.10.08 22:42) [51]
> Ваш способ нафиг и я объяснил почему.

Способ не мой, а классический. Легко находится, как указывалось в [39]. Поэтому посылай классиков. И объясняй им же.


> MsGuns ©   (07.10.08 22:47) [52]
> Но что ты скажешь, если и тебе приклеить ярлычок - "догматик" ?

Пожалуйста. Только с обоснованием.


 
MsGuns ©   (2008-10-07 22:58) [57]

Кистати, в ИБ имеется возможность ссылаться в запросах на внешние таблицы, насколько я помню. Эге ж ?


 
Johnmen ©   (2008-10-07 22:59) [58]


> MsGuns ©   (07.10.08 22:50) [54]
> ДЛИТЕЛЬНЫЕ ПИШУЩИЕ ТРАНЗАКЦИИ

С какого они длительные??? Очень даже короткие!


> MsGuns ©   (07.10.08 22:53) [55]
> Что прикажете делать админу БД в этом случае ?

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


 
MsGuns ©   (2008-10-07 23:02) [59]

"Хирургия" вполне обоснованна только в одним случае - если "пакет" порезать на независимые логически завершенные (т.е. целостные) "порции" приемлимых размеров. В этом случае клиент может всегда продолжить прерванную трансмиссию данных с "аварийного" пакета. Тогда конечно, следует работать исключительно по классической схеме, ибо она реально является самой оптимальной для сервера.
Но в сабже, повторяю, ни слова об этом.


 
MsGuns ©   (2008-10-07 23:05) [60]

>Johnmen ©   (07.10.08 22:59) [58]
>С какого они длительные??? Очень даже короткие!

При размере порций в 5000 штук ?

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

Т.е. отресторить базу из бэкапа, предварительно послав на перекур всех юзверей и запустить по новой ? На месте админа я бы такого спесилиста повесил на входе в серверную. За яй... в смысле не за шею ;)


 
kaif ©   (2008-10-08 00:37) [61]

О чем спор?
Создавать временные таблицы в IB не принято.
Хочешь - создавай.

MsGuns ©   (07.10.08 22:53) [55]
>Johnmen ©   (07.10.08 22:50) [53]

Под "целостностью" я в данном случае (первая цитата) имел в виду не нарушение форинкеев, а нечто другое - когда в БД попадут НЕ ВСЕ записи, а только часть, причем абсолютно неизвестно заранее какая


А я как раз имел в виду форинкеи и юниккеи.
И я до сих пор не знаю, как ты собираешься отловить нарушение внешнего ключа при вставке через временную таблицу. У тебя отвалится весь insert into ... select from без всякой информации о том, в какой именно строке это произошло. А при непосредственном импорте у тебя имеется естественная возможность узнать это и что-то предпринять, в зависимости от задачи, например, проигнорировать и пойти дальше.

А насчет "не всех" записей, я уже сказал. Незачем разбивать на пакеты по 5000. Можно и в одной транзакции загнать хоть миллион. Я загонял без проблем. И в случае отката единственная проблема, которая возникнет, это некоторый тормоз по чистке мусора. После одного душного select count(*) из этой таблицы все придет в порядок (кроме размера файла базы, разумеется).

Страх перед откатом больших вставок, я думаю, идет от старых версий IB6.0,  в которых были ошибки в связи с чисткой мусора.
В Firebird 1.5 Final этих ошибок я не обнаружил.


 
Германн ©   (2008-10-08 01:08) [62]


> MsGuns ©   (07.10.08 22:47) [52]
> Я - зловредный и ехидный тип, никого, окромя себя не видящий
> и не слышащий.
>

Самокритика это очень хорошо. :)


 
Johnmen ©   (2008-10-08 09:30) [63]


> MsGuns ©   (07.10.08 23:05) [60]
> При размере порций в 5000 штук ?

Да. Что тут удивительного? Или транзакция в 1-5 сек. считается неприлично длительной?

> MsGuns ©   (07.10.08 23:05) [60]
>> ...прогнать импорт ещё раз.
> Т.е. отресторить базу из бэкапа, предварительно ....

Что за фантазии??? :)
Просто импорт ещё раз. Но, естественно, сам импорт написан не недоучившимся студентом. Т.е., по кр.мере, с грамотной обработкой исключений, возникающих при вставке очередной записи. И БД спроектирована не им же. Т.е., по кр.мере, каждая таблица имеет как минимум уникальный индекс.



Страницы: 1 2 вся ветка

Форум: "Базы";
Текущий архив: 2009.07.05;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.68 MB
Время: 0.006 c
15-1241591266
Медвежонок Пятачок
2009-05-06 10:27
2009.07.05
файерфокс тупит или я


2-1242386967
ford
2009-05-15 15:29
2009.07.05
управление другим приложением


2-1242671998
TStas
2009-05-18 22:39
2009.07.05
Приведение типов в циклах


6-1193474211
9899100
2007-10-27 12:36
2009.07.05
проблемма с соединением TIdFTP


15-1240950597
Юрий
2009-04-29 00:29
2009.07.05
С днем рождения ! 29 апреля 2009 среда





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский