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

Вниз

Удаление большого количества записей firebird 1.5   Найти похожие ветки 

 
Dim!S   (2009-10-28 08:43) [0]

Уважаемые форумчане!

Есть бд на Firebird 1.5 (gdb). Необходимо из неё удалить каждые несколько записей...
вот кусок кода, но иногда программа выдаёт сообщение out of memory
...
IBTable1.DisableControls;
cnt_Rec := 0;
IBTable1.First;

with IBTable1 do
while not(EOF) do
   begin
     IBTable1.First;
     Delete;
     Delete;
     Delete;
     Delete;
     Next;

     Inc(cnt_Rec);
     Application.ProcessMessages;
     if cnt_Rec >= 10000 then
        begin
          ShowMessage(IntToStr(RecNo) + " - " + IntToStr(cnt_Rec));
          cnt_Rec := 0;
          IBTransaction1.Commit;
          IBTransaction1.StartTransaction;
        end;
   end;

IBTransaction1.Commit;
IBTable1.EnableControls;
Label2.Caption := TimeToStr(Time);
IBTable1.Refresh;
...

Как лучше написать код для указанной задачи? Записей в таблице может быть миллион. К базе никто не подключен... Может лучше через IBQuery ии есть более изящный способ?

P.S. с firebird дело не имел вообще, только с paradox

Большое спасибо.


 
sniknik ©   (2009-10-28 09:02) [1]

> Может лучше через IBQuery
неважно через что... главное запросом. (а то ты счас поменяешь компонент с IBTable1 на IBQuery а код оставиш неизменным...)


 
Sergey13 ©   (2009-10-28 09:31) [2]

Честно говоря, чуднее алгоритма удаления из таблицы я не встречал. Типа оставить только каждую пятую запись? Похоже на прореживание моркови на грядке.
А смысл этого действа, если не сложно, можешь рассказать?


 
Сергей М. ©   (2009-10-28 09:54) [3]


> Записей в таблице может быть миллион


А может быть и не миллион, а, скажем, всего дюжина.
И тогда грабли хлобыстнут еще больней, чем по out of memory


 
Dim!S   (2009-10-28 10:55) [4]

>Sergey13 а в чём чудность? Ну если так нао, именно каждые 4 или 5 или 6 записей оставляя следующую. Не спрашивайте зачем ;)

>Сергей М. грабли на таблице в 50 МБ (150 тыс) не бьют :) а вот больше засада...

>All Форумчане! Дайте, пожалуйста, намётки на реализацию этой задачи...Я предполагаю так:

начинаем транзакцию
удаляем (допустим 50 тыс. записей)
заканчиваем транзакцию

и это в цикле от первой записи до последней
С реализацией туговато, ввиду отсутствия практического опыта работы с FireBird...

Спасибо.


 
Сергей М. ©   (2009-10-28 11:00) [5]


> С реализацией туговато, ввиду отсутствия практического опыта
> работы с FireBird


Те же самые грабли хряснут по тому же самому месту и в Парадоксе.
СУБД здесь ни причем.


> грабли на таблице в 50 МБ (150 тыс) не бьют


Понатыкай в тело цикла вместо четырех 150 тыс. вызовов метода delete - лупанут всенепременно)


 
sniknik ©   (2009-10-28 11:00) [6]

> Не спрашивайте зачем ;)
> Я предполагаю так:
http://delphimaster.net/view/2-1256632484/
в [28] там ссылка на хорошую статью. мне понравилась. и ведь именно так все и есть...


 
Sergey13 ©   (2009-10-28 11:13) [7]

> [6] sniknik ©   (28.10.09 11:00)
> http://delphimaster.net/view/2-1256632484/
> в [28] там ссылка на хорошую статью.

Шикарно! 8-)

> [4] Dim!S   (28.10.09 10:55)
> Не спрашивайте зачем ;)

Прочитай обязательно статейку!
Ты же просишь "изящный способ", но скрываешь условия. И где логика?


 
Dim!S   (2009-10-28 11:13) [8]

Спасибо за ссылку, гляну...

И всё же, как можно проредить базу данных?
Или лучше создать новую и в неё каждую n-ю запись добавлять?


 
Sergey13 ©   (2009-10-28 11:21) [9]

> [8] Dim!S   (28.10.09 11:13)

Ты сначала глянь, а потом сформулируй вопрос. 8-)


 
Сергей М. ©   (2009-10-28 11:23) [10]


> как можно проредить базу данных?


Значит все-таки морковка)

Ну ты сам посуди - флаг EOF ты проверяешь всего один раз перед каждой итерацией цикла. А в теле цикла ты беспардонно пытаешься удалить столько записей, сколько тебе захотелось, нисколько не задумываясь о том, что при очередном delete или next этот флаг может принять значение True !


 
Dim!S   (2009-10-28 15:12) [11]

"флаг EOF ты проверяешь всего один раз перед каждой итерацией цикла" -
ну конечно же!!! Большое спасибо....

И всё-таки морковка... :)
Форумчане, подскажите кусочек кода по оптимальному прореживанию БД. Спасибо.


 
Sergey13 ©   (2009-10-28 15:48) [12]

> [11] Dim!S   (28.10.09 15:12)

> Форумчане, подскажите кусочек кода по оптимальному прореживанию БД. Спасибо.

delete from tablename
truncate table tablename


 
Сергей М. ©   (2009-10-28 16:07) [13]


> подскажите кусочек кода по оптимальному прореживанию БД


Просто интересно, кто же так густо засадил эту грядку, как часто придется ее прореживать и что потом делать с урожаем ?


 
Dim!S   (2009-10-28 16:42) [14]

действительно интересно? ;)

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

По теме можете что сказать?


 
Sergey13 ©   (2009-10-28 16:58) [15]

> [14] Dim!S   (28.10.09 16:42)

Все таки не прочитал ты статью по ссылке. Жаль.


 
Сергей М. ©   (2009-10-28 17:10) [16]


> Необходимо часть сведений из бд убирать


Так вот и интересно, по какому критерию требуется осуществлять "прореживание" ?

Четыре очередные морковки дергаем, следующую пятую оставляем, пока либо не подрали всю грядку либо количество этих телодвижений (4 дернули, одну оставили) не превысило 10000,
так что ли ?)


 
Dim!S   (2009-10-28 17:16) [17]

"все таки не прочитал ты статью по ссылке. Жаль" - прочитал... :) про x, y, z ... :) занятно...

отбор будет по критерию 4 выдернули одну оставили из всей таблицы. Возможно условие отбора будет изменено, но мне главное как корректно пройти всю таблицу на предмет прореживания. Пусть будет и не 4 выдернули одну оставили, а по условию проверки значения поля через if c несколькими ветками - неважно, главное как проредить всю таблицу - быстро и корректно.

Спасибо.


 
Сергей М. ©   (2009-10-28 17:36) [18]

счетчик_последовательно_выдернутых_морковок = 0

подойти к началу грядки;

пока не конец грядки делать
начало
  если счетчик_последовательно_выдернутых_морковок < 4 то
  начало
    выдернуть морковку (нос при этом автоматически уткнется или в следующую морковку или в конец грядки)
    увеличить  счетчик_последовательно_выдернутых_морковок на 1
  конец
  иначе
  начало
     счетчик_последовательно_выдернутых_морковок = 0
     передвинуть нос к возможной следующей морковке
 конец
конец


 
Dim!S   (2009-10-28 17:51) [19]

:) ок, получается:
с использованием IBTable

procedure DelRec;
var cnt_Rec: longint; //наврядли будет больше 2 млрд. записей :)
begin
with IBTable do
  begin
      First;

      cnt_Rec := 0;

      while not(EOF) do
           if cnt_Rec < 4 then
              begin
                 if EOF then Break; //а вдруг конец таблицы достигнем в цикле (спасибо Сергей М. за подсказку)

                 Delete;
                 Inc(cnt_Rec);
              end else
              begin
                 cnt_Rec := 0;
                 Next;
              end;
  end;
end;

Интересует как это всё завернуть в транзакции, где ставить StartTransaction и Commit?

Как реализовать это через IBQuery (и надо ли? будет ли какой-то выигрыш от перехода на IBQuery, если бд будет обрабатываться на сервере)?


 
Виталий Панасенко(дом)   (2009-10-28 18:16) [20]

странный вопрос... где тебе нужно, там и ставь.. только от Out of memory На больших НД это тебя вряд ли спасет


 
Dim!S   (2009-10-28 18:20) [21]

Сколько можно максимум обработать (удалить) записей за одну транзакцию? Как обойти ошибку Out Of Memory на больших НД? Наврядли нужно каждую запись удалять через транзакцию - слишком накладно будет...


 
Виталий Панасенко(дом)   (2009-10-28 18:23) [22]

вот именно, накладно...


 
Виталий Панасенко(дом)   (2009-10-28 18:37) [23]

обойти нехватку памяти.. попробуй Unidictional=True, добавить памяти, увеличить своп


 
Dim!S   (2009-10-28 18:45) [24]

Unidirectional=True - как я понял при удалении записей некорректно себя ведёт IBTable c этим параметром в true... Скачет по таблице не по порядку или я заблуждаюсь...


 
Dim!S   (2009-10-28 18:51) [25]

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

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


 
sniknik ©   (2009-10-28 19:26) [26]

> - прочитал... :) про x, y, z ... :) занятно...
ага.
- вы алгебру вообще читали?
- читал, а как же, ее еще в конце убили...

на на свою ситуацию эти x, y, z переложить не в силах? ведь один в один все получается... если счас сказать как-же все таки сделать, то пойдешь ты радостно доделывать своего монстра (и как там дальше по тексту?)
а запросы (правильный z путь) попросту игнорируешь (не понимаешь что это/понимаешь неправильно, а считаешь что совет неправильный, и т.д. неважно по какой причине, но сделал вид, что никто ничего про них не говорил... точно как в статье).


 
Сергей М. ©   (2009-10-28 20:17) [27]


>       while not(EOF) do
>            if cnt_Rec < 4 then
>               begin
>                  if EOF then Break; //а вдруг конец таблицы
> достигнем в цикле (спасибо Сергей М. за подсказку)


С какого перепугу этот "а вдруг" может приключиться ?


 
SergP ©   (2009-10-28 21:10) [28]


> Пусть будет и не 4 выдернули одну оставили, а по условию
> проверки значения поля через if c несколькими ветками -
> неважно, главное как проредить всю таблицу - быстро и корректно.
>


А не проще используя SQL-запрос
типа delete from table where [твое условие]
?


 
Amoeba ©   (2009-10-29 01:20) [29]


> А не проще используя SQL-запрос
> типа delete from table where [твое условие]

И не просто проще, а только так и не иначе.


 
Германн ©   (2009-10-29 01:39) [30]


> Есть бд на Firebird 1.5

Были какие-то похожие глюки с 1.5.
Стоит поискать на ibase.ru сведения о багах версий 1.5.x

P.S. Но все предыдущие замечания знатоков работы с БД, я не отрицаю.


 
PEAKTOP ©   (2009-10-29 02:33) [31]

Весело здесь у вас, ребята...
Не, ну правда.

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

На 12(!) посте была попытка намекнуть на то, что пора бы уже открыть для себя SQL-оператор DELETE, но все присутствующие ее упорно игнорируют и продолжают рассматривать варианты с шести и семиугольными колесами...

На 29(!) посте наконец-то кому-то все-таки приходит мысль: о, блин, точно ! оператор DELETE! Но это не останавливает участников обсуждения и рассматривается вариант: а может на велосипед поставить гусеницы ? а то с колесами у него говорят баги...

Я фигею, дорогая редакция...  :(


 
Германн ©   (2009-10-29 02:43) [32]


> PEAKTOP ©   (29.10.09 02:33) [31]
>
> Весело здесь у вас, ребята...
> Не, ну правда.

"Дорогая передача!
Во субботу, тут, не плача
Вся Канатчикова дача..."
И т.д.
Тем и живём. :)
На "исходниках" уж очень скушно. А на Королевстве - всё зашорено.


 
Dim!S   (2009-10-29 03:02) [33]

1.         if cnt_Rec < 4 then
             begin
                if EOF then Break; //а вдруг конец таблицы достигнем в цикле (спасибо Сергей М. за подсказку)

                Delete;
                Inc(cnt_Rec);
             end else
             begin
                cnt_Rec := 0;
                Next;
             end; //после этого места возвращаемся к началу ветки if
и пытаемся удалить очередные 4 записи

На деле будет такая ситуация:
в таблице 8 записей
после первого прохода осталось 4 записи курсор встал на 2 запись;
во время второго прохода после удаления 4 записи (2 шаг цикла) мы пытаемся удалить 5 - не существующую запись! - получаем ошибку. Для исключения ошибочной ситуации и проверяем остижение конца таблицы...

2. ну так я ещё в первм посте писал "Может лучше через IBQuery ии есть более изящный способ?" - но конкретного ответа не получил, а именно:

"Интересует как это всё завернуть в транзакции, где ставить StartTransaction и Commit?

Как реализовать это через IBQuery (и надо ли? будет ли какой-то выигрыш от перехода на IBQuery, если бд будет обрабатываться на сервере)?"

3. Чем всё-таки плох IBTable в данной ситуации по сравнению с IBQuery?

P.S. с удовольствием готов пойти по правильному пути, только зная почему нужно делать так, а не иначе...


 
PEAKTOP ©   (2009-10-29 03:40) [34]

> P.S. с удовольствием готов пойти по правильному пути, только
> зная почему нужно делать так, а не иначе...


пилять...


procedure DeleteRecords;
var
 lkTr :TIBTransaction;
 lkSQL :TIBSQL;
begin
 lkTr := TIBTransaction.Create(nil);
 lkTr.DataBase := IBDataBase1;
 lkTr.Params.Clear;
 lkTr.Params.Add("isc_tpb_consistency");
 lkTr.Params.Add("isc_tpb_write");
 lkSQL := TIBSQL.Create(lkTr);
 lkSQL.DataBase := lkTr.DataBase;
 lkSQL.Transaction := lkTr;
 lkSQL.SQL.Text := "DELETE FROM MYTABLE TB1 WHERE (TB1.FIELD = ...) AND (TB1.FIELD2 = ...)";
 lkTr.StartTransaction;
 try
   lkSQL.ExecSQL;
 except
   Dialogs.MessageDlg("Не удалось удалить ....", mtError, [mbOk],0);
   lkTr.Rollback;
 end;
 if lkTr.InTransaction then
   lkTr.Commit;
 lkTr.Free;  // lkSQL.Free будет вызван автоматически, т.к. его Owner = lkTr
end;


 
PEAKTOP ©   (2009-10-29 03:48) [35]

> Как реализовать это через IBQuery (и надо ли? будет ли какой-
> то выигрыш от перехода на IBQuery, если бд будет обрабатываться
> на сервере)?"


Читать для понимания работы с БД вообще и с особенностями Firebird в часности.
1) http://www.ozon.ru/context/detail/id/97142/
2) http://www.ozon.ru/context/detail/id/2496996/

Когда дойдешь до команд SQL, смотри русскоязычную справку c учетом версий сервера Firebird, некоторые команды в InterBase и в Firebird отличаются, некоторых в InterBase вообще нет, а некторорые появились только в недавних версиях сервера и не будут работать, например, в Firebird 1.5/
http://firebirdsql.su/


 
PEAKTOP ©   (2009-10-29 04:09) [36]

> На "исходниках" уж очень скушно.

А ты на sql.ru в ветку Firebird зайди. Там Delphi никто не знает :)

А на Королевстве - всё зашорено.

Я помню описание сего ресурса данное HORRIFIC-ом в журнале XAKEP спец №4 еще в марте 2000 года: "сразу видно, что проект ведет женщина" и что ресурс развивается в сторону своего полного вырождения.

Кстати, страницей ранее тот же автор предсказывал TORRY.NET долгие лета. Как видно, он оказался прав в обоих случаях.


 
Dim!S   (2009-10-29 04:48) [37]

>PEAKTOP Спасибо за код и книги... Первая у меня есть только под Delphi 4.

Не помню где (постараюсь найти), но при поиске инфы по IBTable встретил, что при работе с локальной БД FireBird этот компонент не хуже IBQuery. Так как имел опыт только с Table (Paradox), то решил его использовать, и при обработке получил out of memory - пришлось обратиться к помощи форума, т.к. не хвататает знаний как использовать IBTransaction с IBTable (тем более с IBQuery). Интересует транзакцию можно поставить на весь проход таблицы (думаю не стоит этого делать) или на какой-то блок (по N записей)...

В приведённом коде транзакция охватывает всю обработку таблицы за один проход, так? Какие могут быть проблемы с большими НД (сотни тысяч записей)?

P.S. Всем большое спасибо, но думаю тема не закрыта :)


 
Inovet ©   (2009-10-29 04:56) [38]

> [37] Dim!S   (29.10.09 04:48)

Тут шикник часто пишет про костыли в АДО Table, Query к IBX это тоже применимо - не пользуйся TIBTable


 
Dim!S   (2009-10-29 05:05) [39]

если перейду к firebird то буду пользоваться только IBQuery (FBPlus - рекомендуют). :)
Есть ли задачи где query не эффективен или мало эффективен по сравнению с table?

P.S. программирование не является приоритетным направлением, есть несколько разработанных локальных БД на paradox... по большей части для души...


 
PEAKTOP ©   (2009-10-29 05:57) [40]

> Есть ли задачи где query не эффективен или мало эффективен
> по сравнению с table?
>
> P.S. программирование не является приоритетным направлением,
>  есть несколько разработанных локальных БД на paradox...
>  по большей части для души...


В том то и проблема, что в голове Paradox. Paradox является файловой БД, в которой единицей хранения информации является файл таблицы. Оттого и такая философия работы. TTable открывает доступ к файлу через BDE-API, оттого он (компонент) такой быстрый.

Firebird является потомком (1.5) и внуком (> 2.0) InterBase и философия работы с ним совершенно другая. На сервер передаются запросы (команды SELECT) и команды (INSERT/UPDATE/DELETE), а сервер сам уже управляет данными. Т.е. ни одна из API-функций сервера не имеет доступа к данным, они лишь передают команды серверу, а сервер сам управляет физически файлом базы данных. Поэтому базовым компонентом для работы с базами данных Firebird является TIBSQL, т.е. - "простая команда".

Далее - есть класс TIBCustomDataSet, который инкапсулирует пять классов TIBSQL для формирования набора данных, привычного для философии Delphi. Почему именно пять ?
SelectSQL - для команды SELECT, которая возвращает набор данных.
RefreshSQL - почти идентична команде SelectSQL, необходима для того, чтобы перезагрузить с сервера текущую запись набора данных, если она была изменена.
InsertSQL/UpdateSQL/DeleteSQL - для того, чтобы управлять изменениями в наборе данных.

От класса TIBCustomDataSet порождены классы TIBDataSet, TIBTable, TIBQuery, TIBStoredProc. Наиболее полный доступ к возможностям класса TIBCustomDataSet открывает класс TIBDataSet, позволяя управлять всеми пятью командами SQL. Класс TIBQuery - поскромнее, он позволяет управлять только командой SelectSQL. Класс TIBTable вообще маскирует работы команд SQL, эти команды просто автоматически формируются "внутри" класса таким образом, что у тебя возникает иллюзия будто бы компонент действительно физически работает с таблицей. Нет никакой таблицы. ("Нет никакой ложки..." бу-го-га!) Есть пять команд SQL, которые трудятся в фоне и создают для тебя иллюзию.

Для чего его тогда придумали ? Чтобы программистам в далеком 1999 году с появлением Delphi 5 было легче сломать старые стереотипы программирования, чтобы было перевести свои старые приложения с BDE-архитектуры на архитектуру компонентов IBX (и убедиться, что старая философия программирования, основанная на TTable, в IBX никуда не годится).

Поэтому сравнивать производительность двух классов потомков от одного класса предка - не совсем корректно, т.к. можно привести примеры "в любую сторону", в зависимости от желаемого результата и кривизны рук.



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

Форум: "Начинающим";
Текущий архив: 2009.12.20;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.006 c
2-1256897496
pesad
2009-10-30 13:11
2009.12.20
Быстрая графика


1-1229178246
postedman
2008-12-13 17:24
2009.12.20
Объектный процедурный тип


2-1257241912
Serge
2009-11-03 12:51
2009.12.20
Как сделать перенос текста в заголовке ListView?


15-1256195273
Knight
2009-10-22 11:07
2009.12.20
Напомните, про URL


2-1257182783
STD
2009-11-02 20:26
2009.12.20
Выполнить в фоне





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский