Загрузчик SQL, насыщение триггера?

У меня есть ситуация, которой я не могу найти объяснение, вот оно. (Я буду использовать гипотетическую информацию, так как оригинал действительно большой.)

У меня есть таблица, скажем:

table_a
-------------
name
last name
dept
status
notes

И эта таблица имеет триггер на вставку, который выполняет большую проверку информации, чтобы изменить поле состояния новой записи в соответствии с результатами проверки, некоторые из проверок:

- check for the name existing in a dictionary
- check for the last name existing in a dictionary
- check that fields (name,last name,dept) aren't already inserted in table_b
- ... and so on

Дело в том, что если я делаю вставку в таблицу через запрос, например

insert into table_a 
(name,last_name,dept,status,notes) 
values
('john','smith',1,0,'new');

для выполнения всего процесса проверки, обновления поля статуса и вставки записи в таблицу требуется всего 173 мс. (процесс проверки выполняет все поиски по индексам)

Но если я попробую это через SQLloader, прочитав файл с 5000 записями, потребуется около 40 минут для проверки и вставки 149 записей (конечно, я его убил...)

Итак, я попытался загрузить данные, отключив триггер (для проверки скорости), и я получил, что он загружается, как и все записи, менее чем за 10 секунд.

Итак, мой вопрос: что я могу сделать, чтобы улучшить этот процесс? Моя единственная теория заключается в том, что я мог перегружать базу данных, потому что она загружается так быстро и запускает много экземпляров триггера, но я действительно не знаю.

Моя цель — загрузить около 60 файлов с информацией и проверить их через процесс в триггере (хотя я готов попробовать другие варианты).

Я бы очень признателен за любую помощь, которую вы можете предоставить!

ДОПОЛНЕНИЕ---------------------------------------------------------- ---------------------------------------

Спасибо за ответ, теперь я прочитаю все об этом, теперь надеюсь, что вы можете помочь мне с этой частью. позвольте мне объяснить некоторые функции, которые мне нужны (и я использовал триггер, потому что не мог придумать ничего другого)

поэтому данные таблицы поставляются с этими (важными) полями:

pid name lastname birthdate dept cicle notes

данные приходят вот такие

name lastname birthdate dept

теперь триггер делает это с данными:

  1. Вызывает функцию для расчета pid (вычисляется на основе имени, фамилии и даты рождения с помощью алгоритма)

  2. Вызывает функцию для проверки имен в словаре (это потому, что в моем словаре у меня есть отдельные имена, то есть, если человека зовут Джон Аарон Смит Джонс, функция разбивает Джона Аарона на две части и ищет Джона и Аарона в словаре в отдельные запросы, вот почему я не использовал внешний ключ [чтобы избежать большого количества комбинаций john aaron, john alan, john pierce..etc]) ---> как бы застрял на том, как реализовать это с ключами, не меняя словарь ... может быть, с ПРОВЕРКОЙ ?, внешний ключ фамилии был бы хорошей идеей.

  3. Получает цикл из другой таблицы в соответствии с отделом и текущей датой (поскольку человек может дважды появляться в таблице в одном и том же отделе, но в другом цикле) ---> как я могу получить это значение цикла более эффективным способом для сделать правильный поиск?

  4. И, наконец, после того, как вся эта проверка выполнена, мне нужно точно знать, какая проверка не была выполнена (таким образом, примечания к полю), поэтому триггер объединяет все строки неудачных проверок, например:

    lastname not in dictionary, cannot calculate pid (invalid date), name not in dictionary

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

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


person E. Diaz    schedule 02.07.2013    source источник
comment
Для name и last_name вместо использования триггера рассмотрели ли вы ограничения внешнего ключа, которые ссылаются на таблицу (при условии, что она есть), которая представляет ваш словарь? Для третьей проверки вы имели в виду table_a или table_b? Если вы имели в виду table_a, рассматривали ли вы вместо этого уникальное ограничение? Если вы имели в виду table_b, вы могли бы рассмотреть возможность использования одной таблицы вместо (или в дополнение), чтобы вы могли использовать уникальное ограничение для обеспечения уникальности - удивительно сложно написать триггер, чтобы сделать это правильно при одновременных вставках/обновлениях (вам нужно использовать блокировку).   -  person Brian Camire    schedule 03.07.2013
comment
Насколько велик ваш словарь? Ознакомьтесь со статистикой на сайте Namex namethesaurus.com.   -  person APC    schedule 03.07.2013


Ответы (1)


Вы уже на полпути к решению:

«Поэтому я попытался загрузить данные, отключив триггер (для проверки скорости) ... он загружается, как и все записи, менее чем за 10 секунд».

Это не сюрприз. Ваша текущая реализация выполняет много однострочных операторов SELECT для каждой строки, которую вы вставляете в таблицу B. Это неизбежно приведет к снижению производительности. SQL — это язык, основанный на наборах, и он лучше работает с многострочными операциями.

Итак, вам нужно найти способ заменить все операторы SELECT более эффективными альтернативами. Тогда вы сможете сбрасывать триггеры навсегда. Например, замените поиск в словаре внешними ключами между столбцами таблицы A и справочной таблицей. Ограничения реляционной целостности, будучи внутренним кодом Oracle, работают намного лучше, чем любой код, который мы можем написать (и работают также в многопользовательских средах).

Правило не вставлять в таблицу A, если комбинация столбцов уже существует в таблице B, более проблематично. Не потому, что это сложно сделать, а потому, что это звучит как плохой реляционный дизайн. Если вы не хотите загружать записи в таблицу A, когда они уже выходят из таблицы B, почему вы не загружаете их напрямую в таблицу B? Или, возможно, у вас есть подмножество столбцов, которые должны быть извлечены из таблицы A и таблицы B и сформированы в таблицу C (которая будет иметь отношения внешнего ключа с A и B)?

В любом случае, оставив это в стороне, вы можете сделать это с помощью SQL на основе набора, заменив SQL*Loader внешней таблицей. Внешняя таблица позволяет нам представить файл CSV в базе данных, как если бы это была обычная таблица. Это означает, что мы можем использовать его в обычных операторах SQL. Подробнее.

Таким образом, с ограничениями внешнего ключа на словарь и внешнюю таблицу вы можете заменить код загрузчика SQL этим оператором (с учетом любых других правил, включенных в «... и т. д.»):

insert into table_a
select ext.* 
from external_table ext
     left outer join table_b b
     on (ext.name = b.name and ext.last_name = b.last_name and ext.dept=b.dept)
where b.name is null
log errors into err_table_a ('load_fail') ;

При этом используется синтаксис регистрации ошибок DML для регистрации ошибок ограничений для всех строк на основе набора. Подробнее. Он не вызовет исключения для строк, которые уже существуют в таблице B. Вы можете использовать многотабличный INSERT ALL, чтобы перенаправить строки в таблицу переполнения или использовать операцию набора MINUS после события, чтобы найти строки во внешней таблице, которых нет в таблице A. Зависит от вашего конечная цель и как вам нужно сообщать о вещах.

Возможно, более сложный ответ, чем вы ожидали. Oracle SQL — это очень обширная реализация SQL с множеством функций для повышения эффективности массовых операций. Нам действительно стоит прочитать Руководство по концепциям и Справочник по SQL, чтобы узнать, как много мы можем сделать с Oracle.

person APC    schedule 03.07.2013
comment
Большое спасибо, теперь я расширил информацию, надеюсь, вы сможете просмотреть ее и дать мне несколько советов, спасибо! - person E. Diaz; 03.07.2013