SQL вставить в дочерние и родительские таблицы - PullRequest
4 голосов
/ 30 августа 2011

У меня есть две таблицы с отношением многие-к-одному.(Oracle)

**Table: PARENT**
Field: A (PK)
Field: B
Field: C1
Field: C2
Field: C3
Field: C4
Field: C5

**Table CHILD**
Field: A (PK) (FK to PARENT.A)
Field: D (PK)
Field: E

Записи, вставленные в дочернюю и родительскую таблицы, вставляются одновременно.

Меня интересует, что является наиболее эффективным способом сделать это.

В настоящее время существует одна хранимая процедура, которая вызывается вызывающим приложением для всего шага вставки.Хранимая процедура в настоящее время имеет следующую сигнатуру:

Field: A
Field: B
Field: C (dilimited string)
Field: D (dilimited string)
Field: E (dilimited string)

Процедура перебирает C из входных данных и сохраняет каждое из значений в массиве.Затем использует этот массив вместе с A и B из входных данных для вставки в таблицу PARENT.

Затем использует A из входных данных и проходит через D и E из входных данных и выполняет вставку в таблицу CHILD для каждого элемента.в ограниченных строках.

Это будет вызываться до 3 миллионов раз в день.Он должен быть максимально эффективным.

Какая эффективность теряется при выполнении нескольких вызовов SP, а не только одного?

Все циклы для обработки разделенных строк кажутся многоработы!

Я думал, что вызывающее приложение может сделать отдельные вызовы SP для каждой записи в CHILD.Однако, как я могу гарантировать, что каким-то образом вставка в CHILD не произойдет до вставки в PARENT ... и это будет больше вызовов хранимых процедур.(во многих случаях нет дочерних записей для вставки, когда их обычно меньше 10, но может быть целых 50)

Я также открываю другой способ получения информации в разбавленной строке C.

Есть ли что-то более эффективное, чем цикл while, для получения информации из ограниченных строк?

Я не писал SP, меня попросили сделать небольшую модификацию и сделать ее более эффективной, есливозможно.

Есть идеи?

Примечания:

Я упростил таблицы, на самом деле 10 строк в упрощенной строке C, а не 5, есть также еще две расширенные строки простокак C, которые вставляются в таблицу PARENT.В таблицах также есть несколько полей больше, чем показано

Записи удаляются через 30 дней.

Ответы [ 2 ]

1 голос
/ 30 августа 2011

Здесь есть пара вещей ...

Во-первых, если вы перебираете строку с разделителями, чтобы поместить похожие элементы в одинаковые столбцы, вам, вероятно, потребуется реорганизовать таблицы, чтобы они были более нормализованы. Например, если C представляет собой список телефонных номеров с разделителями, а столбцы C1 - C5 равны phone1 - phone5, вероятно, у вас должна быть отдельная дочерняя таблица phone. Это зависит от варианта использования, но кажется мне потенциальной будущей проблемой (т. Е. Знанием разделителя). Если в строке с разделителями имеются несходные данные (номер телефона, город, имя и т. Д.) - укажите отдельные параметры ввода для каждого отдельного элемента данных. Это еще большая потенциальная проблема (потому что, если порядок записей важен, вы облажались, точка).

Вы правы, цикл по разделенным строкам - это большая работа. Там не обязательно лучший способ сделать это, если, возможно, если ваша СУБД имеет какую-то встроенную функцию split или что-то (или вы можете вызвать внешнюю функцию). Я бы предпочел избежать этого, если бы мог, и вызвать хранимую процедуру child. Это должно быть для каждого ребенка, но это на самом деле лучше в любом случае - не обязательно с точки зрения производительности, но и для концептуализации, и будущего обслуживания.

Как предотвратить вставку строки child без parent? Используйте ограничение внешнего ключа. Если ограничение нарушено, то это ошибка вызывающей стороны, а не базы данных.

Хорошо, некоторые из них требуют серьезных изменений в SP, а некоторые требуют изменений в базовой структуре таблицы (которая, если она была изначально настроена правильно, должна быть в основном прозрачной для пользователей) , Но это то, что я бы попытался ...

О, и, пожалуйста, скажи мне, что все это работает под контролем обязательств ...

0 голосов
/ 31 августа 2011

Наиболее эффективный способ справиться с этим, вероятно, заключается в использовании пользовательских типов данных для вставки списков значений в хранимую процедуру в виде массивов, а не в виде строк с разделителями.Примерно так:

CREATE TYPE r_child IS OBJECT
   (a NUMBER, d VARCHAR2(20), e VARCHAR2(20));

CREATE TYPE nt_child AS TABLE OF r_child;

CREATE TYPE nt_c AS TABLE OF VARCHAR2(20);

CREATE PROCEDURE insert_data(
   p_a NUMBER, p_b VARCHAR2, p_c nt_c,
   p_child nt_child
) AS
   v_parent   parent%ROWTYPE;
   i          NUMBER;
BEGIN
   v_parent.a   := p_a;
   v_parent.b   := p_a;

   FOR i IN p_c.FIRST .. p_c.LAST LOOP
      CASE i
         WHEN 1 THEN
            v_parent.c1   := p_c(i);
         WHEN 2 THEN
            v_parent.c2   := p_c(i);
         WHEN 3 THEN
            v_parent.c3   := p_c(i);
         WHEN 4 THEN
            v_parent.c4   := p_c(i);
         WHEN 5 THEN
            v_parent.c5   := p_c(i);
      END CASE;
   END LOOP;

   INSERT INTO parent(
                         a,
                         b,
                         c1,
                         c2,
                         c3,
                         c4,
                         c5
              )
   VALUES     v_parent;

   FORALL i IN p_child.FIRST .. p_child.LAST
      INSERT INTO child(
                           a, d, e
                 )
      VALUES     (
                     p_a, p_child(i).d, p_child(i).e
                 );
END insert_data;

Упаковка вставок в пакет не увеличит время выполнения, если пакет хорошо спроектирован.Это включает в себя использование массовых вставок (как показано там, где я использовал forall) и использование структур данных, которые база данных может читать естественным образом, вместо кодирования и декодирования данных (как вы в настоящее время делаете со значениями с разделителями).

...