Доброго времени суток.
Нужен совет по реализации.
Есть несколько dbf файлов (используется TDBF) и из них нужно собирать сводную таблицу, т.е. поле одного файла ссылается на поле другого и т.д.
В данный момент реализовано таким образом:
В цикле
1) берем значение поля из записи первого файла
2) фильтруем второй файл по найденному значению и берем значение из одного поля найденной записи
3) фильтруем третий файл по найденному значению и берем значение из одного поля найденной записи
4) фильтруем четвертый файл по найденному значению и берем значение из одного поля найденной записи
5) фильтруем пятый файл по найденному значению
конец цикла
На каждом этапе некоторые поля выводятся в stringgrid.
При этом первый файл может быть до 100000 записей, второй до 30000, 3-5 в пределах 1500 записей.
При размере первого файла в 600 записей, второго в 6000 формируется порядка 30 секунд.
Нужны советы как ускорить обработку.
Заренее благодарен за советы.
P.S. dbf файлы менять нельзя, т.к. они используются другой программой.
Как ускорить обработку dbf файлов
Модератор: Модераторы
-
sobee
- новенький
- Сообщения: 84
- Зарегистрирован: 04.02.2008 23:23:46
- Откуда: Снежинск, Челябинская обл.
Использование индексов решит проблему. Создай предварительно по всем вариантам выборки индексный(е) файл(ы). При этом при выборе в файле источнике в связанном файле записи автоматически сортируются по выбранному значению ключа (тегу).
Мне нужна быстрая выборка записей по полю KVED, я добавил вот такой код для создания индекса
файл abon.ndx создается, а что дальше понять не могу...
Ради любопытства попробовал showmessage(intToStr(abon.IndexDefs.Count)) (как я понял должно показать количество используемых индексов), но получаю 0.
Подскажите как дальше делать выборку.
До этого никогда с индексами не работал.
Код: Выделить всё
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 07:56:42, всего редактировалось 1 раз.
Velial
Как только Вы назначили текущий индекс, дальше Вы работаете как обычно. Теперь TDbf для поиска и фильтрации и данных использует данные индекса, где данные отсортированы в правильном порядке. Время обработки уменьшается за счёт того, что теперь не надо просматривать всю таблицу целиком.
Как только Вы назначили текущий индекс, дальше Вы работаете как обычно. Теперь TDbf для поиска и фильтрации и данных использует данные индекса, где данные отсортированы в правильном порядке. Время обработки уменьшается за счёт того, что теперь не надо просматривать всю таблицу целиком.
То есть дальше я могу просто перебирать таблицу с помощью dbf1.first, dbf1.next и она должна быть уже отсортирована(я никак больше не упоминаю ничего связаного с индексами)?
Если я связываю tdbf - TDatasource - DBGrid , то в гриде записи должны осортироваться? У меня не сортируются...
Добавлено спустя 1 час 22 минуты 33 секунды:
После создания индекса с помощью таблица становится сортированой, это конечно хорошо, но столкнулся с другой проблемой:
до этого я выбирал нужные записи :
Теперь при таком методе поиска время обработки увеличилось почти в 10 раз... Что я делаю не так?
Или мне делать поиск нужной записи перебором с помощью 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 ? Но тогда я не вижу особого смысла(возможно проблема со зрением
Попробуйте связать таблицы, как master-detail, если у TDbf есть свойство MasterSource (или оно может называться DataSource почему-то).
А можно по подробнее?
Добавлено спустя 2 часа 16 минут 35 секунд:
Сейчас имею вот такой код:
но как получить значение из dbf2 соответствующее текущей записи dbf1 ?
Добавлено спустя 1 час 26 минут 26 секунд:
Проблема решена. Увеличение скорости в 5 раз. Вот такой код получился(Может кому-то пригодится):
Всем спасибо за помощь.
Добавлено спустя 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;
Всем спасибо за помощь.
