Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Не пойму, почему долго работает следующий код [D7, FireBird 1.5.3]


Страницы:   1 2

pavel_guzhanov ©   (2007-05-02 08:47:00) 

 IBDSFil.SelectSQL.Clear;
 IBDSFil.SelectSQL.Add('select memb_id, fio, Card_ser, Card_no from Table1 where not fio like ('+'''%СОЛИДАРНЫЙ%'''+') order by memb_id');
 IBDSFil.Open;
//Этот запрос отрабатывает мгновенно и возвращает 50000 записей
 IBDSFil.FetchAll;
 Rec:=IBDSFil.RecordCount;
 PB.Min:=0;// прогрессбар
 PB.Max:=Rec;
 IBDSFil.First;
 while not IBDSFil.Eof do
 begin
   IBQRefSel.Close;
   IBQRefSel.Params[0].Value:=Filial_no;
   IBQRefSel.Params[1].Value:=IBDSFil.FieldByName('MEMB_ID').AsInteger;
   IBQRefSel.Open;
// это тоже отрабатывает моментально
   PB.Position:=PB.Position+1;
   if IBQRefsel.IsEmpty then // все 50000 записей удовлетворяют условию
   begin
     IBQRef.Close;
     IBTransaction2.Active:=true;
     IBQRef.Params[0].Value:=Filial_no;
     IBQRef.Params[1].Value:=IBDSFil.FieldByName('MEMB_ID').AsInteger;
     IBQRef.Params[2].Value:=IBDSFil.FieldByName('FIO').AsString;
     IBQRef.Params[3].Value:=IBDSFil.FieldByName('CARD_SER').AsString;
     IBQRef.Params[4].Value:=IBDSFil.FieldByName('Card_no').AsInteger;
     IBQRef.ExecSQL;
   end;
   IBDSFil.Next;
 end;
 IBTransaction2.Commit;
 ShowMessage('Загрузка завершена');


При работе получается 50000 записей. Они все в цикле грузятся в другую базу. Загрузка длится более 30 минут. Я пробовал активировать транзакцию на каждый инсерт, и в конце инсерта делал commit, пробовал все инсерты загружать одним commit'ом, пробовал делать 3000 инсертов в один commit, в любом случае загрузка идет более 30 минут. Подскажите пожалуйста, как можно оптимизировать этот участок кода?

PS Использую стандартные компоненты InterBase. База путая.

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


Asail   (2007-05-03 17:40:00) [1]


> Причем тут индексы на внешние таблицы?

А я и не говорил про индексы на внешние таблицы... Я говорил про индексы на таблицу-приемник. Если они плохо спроектированны - не помогут ни внешние таблицы, ни внутрение, ни любые другие, если перед каждой вставкой проверять запись на наличие!

P.S. Хотя есть и другие вар-ты.


Desdechado   (2007-05-03 12:47:00) [2]

> Не поможет, если индексы неправильные.
Причем тут индексы на внешние таблицы?


pavel_guzhanov   (2007-05-03 08:43:00) [3]


> Asail   (02.05.07 19:25) [20]


Спасибо огромное!!!! Добавил индекс по FILIAL_NO и MEMB_ID, после этого 50000 записей загрузились примерно секунд за 10.


> Кстати, зачем два индекса на поле FIO.


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


atruhin   (2007-05-03 06:16:00) [4]

50 тыс. записей вставить с клиента это фигня. Гадать же что и где автор сделал, по данному куску кода можно долго.
Где текст запросов для IBQRefSel, IBQRef, где скрипты таблиц. На том же SQL.RU без этого даже отвечать не стали.


Asail   (2007-05-02 21:42:00) [5]


> Искать в справке CREATE TABLE ... EXTERNAL FILE

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


Desdechado   (2007-05-02 20:17:00) [6]

FieldByName - тоже небыстрая операция, особенно для большого числа полей и в цикле.

pavel_guzhanov ©   (02.05.07 15:59) [17]
Искать в справке CREATE TABLE ... EXTERNAL FILE


Asail   (2007-05-02 19:25:00) [7]


> В таблице есть два индекса на поле FIO


Я, думаю, понял в чем дело... Перед каждой вставкой ты проверяешь наличие записи в приемнике. Причем ищешь по полям Filial_no и MEMB_ID, но индекса по ним у тебя нет, так? Таким образом твой запрос должен просканировать ВСЮ таблицу, которая с каждым разом все больше и больше... Добавь индекс по Filial_no и MEMB_ID и все должно быть ОК.

Кстати, зачем дваиндекса на поле FIO.


pavel_guzhanov   (2007-05-02 16:24:00) [8]

попробовал заремарчить строки

    IBQRef.ExecSQL;
и
IBTransaction2.Commit;

Бегает все на ура... Получается, что все тормоза в загрузке....


Sergey13   (2007-05-02 16:09:00) [9]

> [17] pavel_guzhanov ©   (02.05.07 15:59)

Я с ними не работал, но вроде как объявляются в ОБЕИХ БД одинаковые внешние таблицы, указывающие на один и тот же файл. Закачав туда данные в одной БД (обычным запросом), в другой можно их тут же прочитать и вставить (опять же обычным запросом) в обычную таблицу.


pavel_guzhanov   (2007-05-02 15:59:00) [10]


> Таки я напомню про внешние таблицы.


Что-то я не соображу, как это сделать...


pavel_guzhanov   (2007-05-02 15:58:00) [11]


> А что по-поводу [7] п.2?


В таблице есть два индекса на поле FIO


> Двигать ProgressBar не после каждой записи, а, например,
>  после каждых 500 записей (~ 1%).


Progressbar вообще убрал, но скорость не изменилась.....


Sergey13   (2007-05-02 15:54:00) [12]

Таки я напомню про внешние таблицы. Ничего тащить вообще не надо.


pavel_guzhanov   (2007-05-02 15:53:00) [13]

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


Asail   (2007-05-02 15:02:00) [14]

А что по-поводу [7] п.2?


pavel_guzhanov   (2007-05-02 14:54:00) [15]


> А у тебя там триггеров, часом, нет?

Есть. Он запускает генератор, который генерит айдишник при вставке


Asail   (2007-05-02 14:28:00) [16]

А у тебя там триггеров, часом, нет?


pavel_guzhanov   (2007-05-02 13:26:00) [17]

Сделал процедуру в базе, стало даже медленнее. В процедуру вынес проверку на повтор и инсерт.


ANB   (2007-05-02 10:50:00) [18]


> Но и тащить можно все скопом (клиентский курсор) или по
> одной (серверный курсор).

50000 записей - малый объем. Серверный курсор вряд ли прибавит скорости.


ЮЮ   (2007-05-02 10:34:00) [19]

> Нет. Так-что по-любому все записи на клиента тащить. :-(

Но и тащить можно все скопом (клиентский курсор) или по одной (серверный курсор).


Asail   (2007-05-02 09:43:00) [20]


> З.Ы. а FireBird гетерогенные запросы (одновременно к двум
> базам) не поддерживает?

Нет. Так-что по-любому все записи на клиента тащить. :-(
Попробуй:
1. Двигать ProgressBar не после каждой записи, а, например, после каждых 500 записей (~ 1%).
2. В таблице из которой IBQRefSel читает убедись, что выборка работает исключительно по индексу.
3. Как уже было сказанно, делай Prepare всем многократно запускаемым запросам перед началом работы (не забудь UnPrepare по окончанию).


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо