Нужен совет по лучшему способу фильтрации текстовых файлов на основе справочной таблицы

Сейчас я ищу способ оптимизировать процесс,
который занимает много времени.

  • Необходимо отфильтровать около 270 текстовых файлов.
  • В каждом файле около 70-150 тысяч строк.
  • Справочная таблица обычно содержит около 16 млн записей в Oracle 10g.
  • Процесс выполняется каждый час.
  • Существует вероятность того, что 9 экземпляров этого процесса могут быть запущены почти
    одновременно.

Что я сейчас делаю, так это помещаю справочную таблицу в файл, копирую ее
в хэш, делаю то же самое с текстовым файлом, затем сопоставляю хэш-ключ.
Любая запись в текстовом файле, найденная в список ссылок будет удален.

Это повторяется для всех 270 файлов, однако часть буферизации выполняется
только один раз в начале.

Однако этот подход потребляет от 300 МБ до 500 МБ ОЗУ, а с возможностью
одновременного запуска нескольких экземпляров этого процесса
это кошмар для нашего сервера.

Любые идеи, как это сделать лучше?


person cr8ivecodesmith    schedule 24.02.2012    source источник


Ответы (2)


Я бы посоветовал вам загружать только данные БД в память и обрабатывать такие файлы (извините, это псевдокод, но вы должны получить представление и реализовать его на Perl):

HashSet dbData = GetDataFromDB();
foreach(filename in filenames) {
    FileHandle handle = OpenRead(filename);
    FileHandle tmphandle = OpenWrite(filename + ".tmp");
    while(string line = handle.ReadLine()) {
        if(!dbData.Contains(line)) {
            tmphandle.Write(line);
        }
    }
    tmphandle.Flush();
    tmphandle.Close();
    handle.Close();
    Delete(filename);
    Rename(tmpfilename, filename);
}

Это займет примерно столько же оперативной памяти, сколько занимает ваша справочная таблица.

person penartur    schedule 24.02.2012

Это похоже на то, что можно было бы эффективно сделать в базе данных (большое антисоединение).

Для чтения файлов и сравните их непосредственно с вашей справочной таблицей. Вы можете использовать функцию-оболочку для непосредственного выбора вашего файла:

CREATE OR REPLACE TYPE tab_varchar AS TABLE OF VARCHAR2(4000);
/

CREATE OR REPLACE FUNCTION select_file(p_dir VARCHAR2, p_file VARCHAR2)
   RETURN tab_varchar
   PIPELINED IS
   l_file utl_file.file_type := utl_file.fopen(p_dir, p_file, 'r', 4000);
   l_line VARCHAR2(4000);
BEGIN
   LOOP
      BEGIN
         utl_file.get_line(l_file, l_line);
      EXCEPTION
         WHEN No_Data_Found THEN
            EXIT;
      END;
      PIPE ROW (l_line);
   END LOOP;
   utl_file.fclose(l_file);
   RETURN;
END;
/

Это позволит вам напрямую выбирать ваши данные, например, это вернет содержимое файла C:\tmp\a.txt

create directory tmp_dir as 'C:\tmp\';

select column_value from table(select_file('TMP_DIR', 'a.txt'));

Отсюда для каждого файла должен быть один запрос, например:

INSERT INTO ref_table r
   (SELECT column_value
      FROM table(select_file(:dir, :file_name)
     WHERE column_value NOT IN (SELECT ref_value
                                  FROM ref_table
                                 WHERE ref_value IS NOT NULL)
       AND column_value IS NOT NULL);
person Vincent Malgrat    schedule 24.02.2012