Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Базы данных и репортинг > как ускорить процесс поиска


Автор: marhatter 18.1.2010, 18:50
Здравствуйте. Тип базы данных - dBase, способ доступа к базе - BDE. Есть 7 таблиц. В первой хранится общее количество искомых значений (их количество - 556320). Остальные 6 разбиты по 2 таблицы, то есть существует 3 района. у каждого района по 2 таблицы. По выбранному значению из первой таблицы(она является 7-ой таблицей), ищем соответствующие значения по первой таблице района, то есть дубликаты этих значений. Если такое значение есть в первой таблице района, смотрим что бы поле вторую таблицу района. Например:
Выбранное значение из общей таблицы - 1234567, в цикле проверяем это значение в первых таблицах всех районов, если нашли в каком то районе, то идем во вторую таблицу и смотри там поле ххх, его значение может быть - 1, 2, 6. Если для найденного значения, поля ххх, в разных районах, одинаковы или или в пределах 1, 2, то он нам нужен. Таблицы районов связываются по полю ууу. 
Например :
1)
1 - ый район - значение - 1234567, ххх - 1
2 - ой район - значение - 1234567, ххх - 1
значение 1234567 нужно.
2) 
1 - ый район - значение - 9876543, ххх - 1
2 - ой район - значение - 9876543, ххх - 6
значение 9876543 не нужно.
Делаю вот так
Код

procedure TForm1.N1Click(Sender: TObject);
begin
  t1 := 'C:\1.dbf'
  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Add('SELECT DISTINCT t.PERS_NUM AS CHET');
  Query1.SQL.Add('FROM ''' + t1 + ''' AS t');
  Query1.Open;
  Query1.First;
  while not Query1.Eof do
  begin
    chet := Query1.FieldByName('chet').AsString;
    if (chet <> '') then
    begin
      find(chet, 0);
    end;
    Query1.Next;
  end;
end;
procedure TForm1.Find(num_pers: string; count : Integer);
begin
 str := '';
 if (FindFirst('C:\' + '*.*', faDirectory, sr) = 0) then
      begin
        repeat
          begin
            if ((sr.Name = '.') or (sr.Name = '..') or (sr.Name = '4')) then continue;
            t2 := 'C:\base\' + sr.Name + '\2.dbf';
            t3 := 'C:\base\' + sr.Name + '\3.dbf';
            Query2.Close;
            Query2.SQL.Clear;
            Query2.SQL.Add('SELECT t2.PERS_NUM AS CHET');
            Query2.SQL.Add('FROM ''' + t2 +''' AS t2');
            Query2.SQL.Add('WHERE (t2.PERS_NUM = :par) AND (t2.NUM IN (');
            Query2.SQL.Add('SELECT t3.NUM AS NUM');
            Query2.SQL.Add('FROM ''' + t3 + ''' AS t3');
            Query2.SQL.Add('WHERE (t3.SV IN(1,2) ) and (t3.NUM = :par)');
            Query2.ParamByName('par').Value := num_pers;
            Query2.Open;
            chet1 := Query2.FieldByName('CHET').AsString;
            if (chet1 <>  '') then
            begin
              count := count + 1;
              str := str + ', ' + sr.Name;
            end;
          end;
        until FindNext(sr) <> 0;
      end;
      if (count >= 2) then
      begin
        Memo1.Lines.Add('');
        Memo1.Lines.Add('----- ЛИЦЕВОЙ СЧЕТ ' + num_pers + ' НАЙДЕН в ' + str);
      end;
end;


Пробывал искусственно вводить такое значение в начало общей таблицы, все находит. Но если оно не в начале... Значения из общей таблицы перебирает примерно - одно значение в 5 секунд, всего значений 556320, ну соответсвтенно если вычислить время завершения...очень долго придется ждать. Как ускорить перебор значений? Что я неправильно делаю? Заранее спасибо.

Автор: Vas 18.1.2010, 19:22
Иднексы + SQL запросы, должно быть быстрее, чем в цикле. И вложенные запросы попробуйте вынести отдельно, выполнить его, получить значения, а потом вставить ввиде строки со значениями для нахождения вхождения в множество (то бишь IN).
Просто одному борланду известно как БДЕ работает со вложенными запросами, но что-то мне кажется что для каждой строки таблицы пытается выполняться подзапрос.

Автор: marhatter 18.1.2010, 19:27
Цитата(Vas @ 18.1.2010,  19:22)
Иднексы + SQL запросы, должно быть быстрее, чем в цикле.

то есть примерно так
Код

Query2.Close;
Query2.SQL.Clear;
Query2.SQL.Add('SELECT t2.PERS_NUM AS CHET, t2.NUM  AS NUM');
Query2.SQL.Add('FROM ''' + t2 +''' AS t2');
Query2.SQL.Add('WHERE (t2.PERS_NUM = :par)');
Query2.Open;
num := Query2.FieldByName('num').AsInteger;
Query3.Close;
Query3.SQL.Clear;
Query3.SQL.Add('SELECT t3.NUM AS NUM');
Query3.SQL.Add('FROM ''' + t3 + ''' AS t3');
Query3.SQL.Add('WHERE (t3.SV IN(1,2) ) and (t3.NUM IN (:par1))');
Query3.ParamByName('par1').Value := num;
Query3.Open;

????

Автор: marhatter 18.1.2010, 19:45
Цитата(marhatter @ 18.1.2010,  19:27)
Цитата(Vas @ 18.1.2010,  19:22)
Иднексы + SQL запросы, должно быть быстрее, чем в цикле.

то есть примерно так
Код

Query2.Close;
Query2.SQL.Clear;
Query2.SQL.Add('SELECT t2.PERS_NUM AS CHET, t2.NUM  AS NUM');
Query2.SQL.Add('FROM ''' + t2 +''' AS t2');
Query2.SQL.Add('WHERE (t2.PERS_NUM = :par)');
Query2.Open;
num := Query2.FieldByName('num').AsInteger;
Query3.Close;
Query3.SQL.Clear;
Query3.SQL.Add('SELECT t3.NUM AS NUM');
Query3.SQL.Add('FROM ''' + t3 + ''' AS t3');
Query3.SQL.Add('WHERE (t3.SV IN(1,2) ) and (t3.NUM IN (:par1))');
Query3.ParamByName('par1').Value := num;
Query3.Open;

????

Не совсем понял, что вы имели в виду.

Автор: Vas 19.1.2010, 08:12
Да примерно так, и еще для полей по которым делается отбор, создать индексы.

Автор: marhatter 19.1.2010, 09:06
Цитата(Vas @ 19.1.2010,  08:12)
Да примерно так, и еще для полей по которым делается отбор, создать индексы.

Для полей созданы индексы

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)