Как ускорить обработку dbf файлов

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Как ускорить обработку dbf файлов

Сообщение Velial » 26.12.2010 17:43:42

Доброго времени суток.
Нужен совет по реализации.
Есть несколько dbf файлов (используется TDBF) и из них нужно собирать сводную таблицу, т.е. поле одного файла ссылается на поле другого и т.д.
В данный момент реализовано таким образом:
В цикле
1) берем значение поля из записи первого файла
2) фильтруем второй файл по найденному значению и берем значение из одного поля найденной записи
3) фильтруем третий файл по найденному значению и берем значение из одного поля найденной записи
4) фильтруем четвертый файл по найденному значению и берем значение из одного поля найденной записи
5) фильтруем пятый файл по найденному значению
конец цикла
На каждом этапе некоторые поля выводятся в stringgrid.
При этом первый файл может быть до 100000 записей, второй до 30000, 3-5 в пределах 1500 записей.
При размере первого файла в 600 записей, второго в 6000 формируется порядка 30 секунд.
Нужны советы как ускорить обработку.

Заренее благодарен за советы.

P.S. dbf файлы менять нельзя, т.к. они используются другой программой.
Velial
новенький
 
Сообщения: 36
Зарегистрирован: 02.07.2010 21:23:11

Re: Как ускорить обработку dbf файлов

Сообщение sobee » 26.12.2010 18:13:25

Использование индексов решит проблему. Создай предварительно по всем вариантам выборки индексный(е) файл(ы). При этом при выборе в файле источнике в связанном файле записи автоматически сортируются по выбранному значению ключа (тегу).
sobee
новенький
 
Сообщения: 84
Зарегистрирован: 05.02.2008 00:23:46
Откуда: Снежинск, Челябинская обл.

Re: Как ускорить обработку dbf файлов

Сообщение Velial » 27.12.2010 21:57:56

Мне нужна быстрая выборка записей по полю KVED, я добавил вот такой код для создания индекса
Код: Выделить всё
  dbf1.Exclusive:=true;
  dbf1.Open;
  Dbf1.AddIndex('abon.ndx','KVED', [ixPrimary, ixUnique]);
  Dbf1.Close;
  Dbf1.Exclusive := false;
  dbf1.Open;
  Dbf1.OpenIndexFile('abon.ndx');
  dbf1.IndexName:= 'abon.ndx';

файл abon.ndx создается, а что дальше понять не могу...

Ради любопытства попробовал showmessage(intToStr(abon.IndexDefs.Count)) (как я понял должно показать количество используемых индексов), но получаю 0.

Подскажите как дальше делать выборку.
До этого никогда с индексами не работал.
Последний раз редактировалось Velial 28.12.2010 08:56:42, всего редактировалось 1 раз.
Velial
новенький
 
Сообщения: 36
Зарегистрирован: 02.07.2010 21:23:11

Re: Как ускорить обработку dbf файлов

Сообщение Vadim » 28.12.2010 05:29:35

Velial
Как только Вы назначили текущий индекс, дальше Вы работаете как обычно. Теперь TDbf для поиска и фильтрации и данных использует данные индекса, где данные отсортированы в правильном порядке. Время обработки уменьшается за счёт того, что теперь не надо просматривать всю таблицу целиком.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Как ускорить обработку dbf файлов

Сообщение Velial » 28.12.2010 08:14:51

То есть дальше я могу просто перебирать таблицу с помощью dbf1.first, dbf1.next и она должна быть уже отсортирована(я никак больше не упоминаю ничего связаного с индексами)?
Если я связываю tdbf - TDatasource - DBGrid , то в гриде записи должны осортироваться? У меня не сортируются...

Добавлено спустя 1 час 22 минуты 33 секунды:
После создания индекса с помощью таблица становится сортированой, это конечно хорошо, но столкнулся с другой проблемой:
до этого я выбирал нужные записи :
Код: Выделить всё
dbf1.Filtered := false;
dbf1.Filter := 'KVED='+ intToStr(RDZ.FieldByName('KOD').AsInteger);
dbf1.Filtered:= true;


Теперь при таком методе поиска время обработки увеличилось почти в 10 раз... Что я делаю не так?
Или мне делать поиск нужной записи перебором с помощью dbf1.next ? Но тогда я не вижу особого смысла(возможно проблема со зрением :) ), т.к. не вижу способа листать записи хотя бы по тысяче, а так получается линейный перебор...
Velial
новенький
 
Сообщения: 36
Зарегистрирован: 02.07.2010 21:23:11

Re: Как ускорить обработку dbf файлов

Сообщение v-t-l » 28.12.2010 09:51:28

Попробуйте связать таблицы, как master-detail, если у TDbf есть свойство MasterSource (или оно может называться DataSource почему-то).
v-t-l
энтузиаст
 
Сообщения: 735
Зарегистрирован: 13.05.2007 16:27:22
Откуда: Belarus

Re: Как ускорить обработку dbf файлов

Сообщение Velial » 28.12.2010 09:56:52

А можно по подробнее?

Добавлено спустя 2 часа 16 минут 35 секунд:
Сейчас имею вот такой код:
Код: Выделить всё
  dbf1.Exclusive:=true;
  dbf1.Open;
  Dbf1.AddIndex('abon.ndx','KVED', [ixPrimary, ixUnique]);
  Dbf1.Close;
  Dbf1.Exclusive := false;
  dbf1.Open;
  Dbf1.OpenIndexFile('abon.ndx');
  dbf1.IndexName:= 'abon.ndx';
  dbf1.First;
  dbf2.Open;
  i:= StringGrid1.RowCount;
  dbf2.MasterSource := datasource1;
  dbf2.MasterFields:= 'KVED';

while not dbf1.EOF do
  begin
    StringGrid1.RowCount := i;
    stringgrid1.Cells[0,i-1]:= IntToStr(dbf1.FieldByName('KVED').AsInteger);
    stringgrid1.Cells[1,i-1]:= IntToStr(dbf2.FieldByName('KOD').AsInteger);
    i := i+1;
    dbf1.Next;
    application.ProcessMessages;
  end;

но как получить значение из dbf2 соответствующее текущей записи dbf1 ?

Добавлено спустя 1 час 26 минут 26 секунд:
Проблема решена. Увеличение скорости в 5 раз. Вот такой код получился(Может кому-то пригодится):
Код: Выделить всё
//создаем индексы на подчиненную таблицу, в которой есть поле KVED
  dbf1.Exclusive:=true;
  dbf1.Open;
  Dbf1.AddIndex('abon.ndx','KVED', [ixPrimary, ixUnique]);
  dbf1.close;
  dbf1.Exclusive:=false;
// открываем таблицу
  dbf1.Open;
  dbf1.OpenIndexFile('abon.ndx');
  dbf1.IndexName:= 'abon.ndx';

  datasource1.DataSet := dbf2; //dbf2 основная таблица

  dbf1.IndexName:='abon.ndx';
  dbf1.MasterSource := datasource1;
  dbf1.MasterFields:= 'KOD'; // поле KOD присутствует в таблице dbf2(основная)
// дальше идет проверка что все работает
  dbf2.Open;
  dbf2.First;
  i:= StringGrid1.RowCount;
while not dbf2.EOF do
  begin
    StringGrid1.RowCount := i;
    stringgrid1.Cells[0,i-1]:= IntToStr(dbf2.FieldByName('KOD').AsInteger);
    stringgrid1.Cells[1,i-1]:= IntToStr(dbf1.FieldByName('KVED').AsInteger);
    i := i+1;
    dbf2.Next;
    application.ProcessMessages;
  end;


Всем спасибо за помощь.
Velial
новенький
 
Сообщения: 36
Зарегистрирован: 02.07.2010 21:23:11


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 15

Рейтинг@Mail.ru