Проверка огромного объема записей в базе данных Oracle .shellscript истекло время ожидания - PullRequest
0 голосов
/ 11 мая 2018

Я работаю над ежедневной автоматизированной работой, которая проверяет записи в текстовом файле с базой данных оракула.Каждый день мы получаем текстовый файл от внешней команды, в которой содержится около 100 000 записей.Текстовый файл будет в формате Unix, который имеет 6 столбцов, разделенных |символ.

например, HDR 1

home/sample/file|testvalue1|testvalue2|testval3|testval4|testval5

TRL

Мне нужно проверить, есть ли значения в testval3 и testval5 в моей таблице в базе данных oracle.В таблице около 10 миллионов записей.Я в настоящее время обрабатываю это через шеллскрипт.Внутри шеллскрипта я читаю текстовый файл и перебираю каждую строку в цикле.Внутри цикла я передаю значение из каждой строки и выполняю запрос к БД.Если записи не существуют в БД, я должен вывести их в CSV-файл.Используется следующий запрос:

select ‘testval3’,’testval5’ from dual 
where not exists (select primarykeycolumn 
from mytable where mycolumn=testval3 and mycolumn2=testval5)

Поскольку входной файл содержит 100000 записей, мой цикл будет выполнять запрос 100000 раз и каждый раз проверять таблицу с 10 миллионами записей.Это заставляет мою пакетную работу работать много часов, и я должен прекратить ее.Есть ли лучший способ справиться с этой ситуацией?Я также могу использовать Java, если нет лучшего способа сделать это с помощью шеллскрипта.

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

Ниже приведено одно из простых решений, которое обеспечит отсутствие тайм-аута, и даже вам не нужно сканировать миллионы записей по 100K раз.

Однократная настройка: Создать промежуточную временную таблицу:

create table a_staging_table(
testvalue1 varchar2(255),
testvalue2 varchar2(255),
testval3 varchar2(255),
testval4 varchar2(255),
testval5 varchar2(255)
);

---- Повторяющийся процесс

Загрузите ваши данные "CSV / TEXT" в промежуточную таблицу:

some_file_name.ctl : этот файл содержит команду загрузки данных ниже.

load data
INFILE 'home/sample/file.csv'
INTO TABLE a_staging_table
APPEND FIELDS TERMINATED BY '|'
(testvalue1,testvalue2,testval3,testval4,testval5);

Теперь запустите загрузчик SQL, чтобы загрузить данные в форму промежуточной таблицы.

sqlldr userid=dbUserName/dbUserPassword control=some_file_name.ctl log=some_file_name.log

Ваши данные загружаются в промежуточные таблицы. Теперь присоединитесь к промежуточной таблице и your_original_table, чтобы определить несуществующую запись.

Первый путь: Буферизируйте вывод из SQL ниже, используя SQL * PLUS:

select s.testval3,testval5
        from (select distinct testval3,testval5 
            from a_staging_table) s 
        where not exists
        (select 1
          from your_original_table
           where mycolumn1=s.testval3
             and mycolumn2=s.testval5);

Второй способ:

Begin
for x in (
    select s.testval3,testval5
    from (select distinct testval3,testval5 
        from a_staging_table) s 
    where not exists
    (select 1
      from your_original_table
       where mycolumn1=s.testval3
         and mycolumn2=s.testval5)
    ) loop

    DBMS_OUTPUT.put_line('testval3: '||x.testval3 || '      ------     '||'testval5: '||x.testval5);
    --write all these values into another file saying that these are not matching values, using UTL_FILE.

--Then finally truncate the table "a_staging_table"
--so that this data will not available next time, and next time again process will run with different file
end loop;
0 голосов
/ 11 мая 2018

Быстрый способ сделать это - собрать все доступные комбинации testval3 и testval5 из таблицы в начале скрипта, сохранить их в хеш-таблице или аналогичной структуре, чтобы при чтении каждой строки вы могли легко запроситьлокальный в структуре данных памяти.

Конечно, он будет использовать больше памяти, но будет выполнять один запрос проверки и многократно ускорить программу.

Запущенный запрос будетselect distinct mycolumn,mycolumn2 from mytable или эквивалент.

См.

Итак, в целом, механизм, который я предлагаю:

  1. Выполнить запрос, чтобы выбрать все отдельные пары testval3 и testval5 из таблицы

  2. Создать хеш-таблицу и конкретную структуру пар, которую вы сохраняетев теме.Например, в Java вы могли бы использовать Коллекция пар Java-значений?(кортежи?) и затем, если типы ваших столбцов являются строками, используйте что-то вроде

HashMap<Pair<String,String>, boolean> pairMap

Убедитесь, что реализован hashCode иметоды equals, как в другом примере ответа, так что вы можете использовать его как ключи на карте (если используете Java или аналогичный)

Сохраните результат запроса в вашей хеш-таблице, имея пары testval3 и testval5 в качестве ключей таблицы и true в качестве значений (способ перебора набора результатов оставлен в качестве упражнения для читателя):

pairMap.put(new Pair<String,String>(testval3,testval5),true)

Читайте файл построчно Строка Foreach, найдите, есть ли пара testval3 и testval5 в вашей хеш-таблице, если она не выводит строку в CSV.Для этого вы можете просто запросить карту и проверить на нулевое значение ( Проверка существования ключа в HashMap )

Например:

 if (pairMap.get(new Pair<String,String>(testval3,testval5)) == null) {
 //output to CSV
 }

Наконец,Другой вариант, о котором говорит @Kaushik Nayak и @Vivek в комментариях, - это загрузить файл в Oracle с помощью инструментов загрузки данных, а затем выполнить один запрос для несуществующих значений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...