Как оптимизировать запрос для обновления столбца таблицы с помощью столбца в другой таблице в oracle - PullRequest
0 голосов
/ 19 февраля 2020

У меня есть 2 таблицы. Одна таблица - cr_archive, в которой содержится около 9000000 записей. У него есть столбец с именем v_sales_person, который не имеет значений. У меня есть другая таблица с именем table_2, которая имеет тот же столбец с именем v_sales_person, в котором есть значения. Обе таблицы имеют столбцы с именем product_label, account_num. Я хочу выбрать данные из таблицы _2, которая имеет те же product_labels и account_num, что и в cr_archive, и обновить столбец v_sales_person в cr_archive значениями в table_2, которые удовлетворяют указанным выше условиям (используя oracle). Я попробовал следующий запрос.

update cr_archive a
set a.v_sales_person = (select distinct b.v_sales_person from table_2 b where a.account_num = b.account_num and A.PRODUCT_LABEL=b.PRODUCT_LABEL )
/
commit
/

Но на обработку запроса уходит более 6 часов, и я не знаю, дает ли он вывод. У меня есть 2 вопроса. 1. Правильный ли приведенный выше запрос? 2. Есть ли способ оптимизировать вышеуказанный запрос.

Ответы [ 2 ]

1 голос
/ 19 февраля 2020

Не используйте select distinct в подзапросе. Предполагается, что он может вернуть более одного ряда. Вместо этого используйте rownum = 1. Итак, начните с:

update cr_archive a
    set a.v_sales_person = (select b.v_sales_person
                            from table_2 b
                            where a.account_num = b.account_num and
                                  A.PRODUCT_LABEL = b.PRODUCT_LABEL and
                                  rownum = 1
                           );

Вы хотите оптимизировать это с индексом на table_2(account_num, PRODUCT_LABEL, v_sales_person). Индекс важен для производительности.

Далее выполняется обновление всех строк. Если это не нужно, это дорого. Итак:

update cr_archive a
    set a.v_sales_person = (select b.v_sales_person
                            from table_2 b
                            where a.account_num = b.account_num and
                                  A.PRODUCT_LABEL = b.PRODUCT_LABEL and
                                  rownum = 1
                           )
    where a.v_sales_person is null or
          a.v_sales_person <> (select b.v_sales_person
                               from table_2 b
                               where a.account_num = b.account_num and
                                     A.PRODUCT_LABEL = b.PRODUCT_LABEL and
                                     rownum = 1
                              );

Наконец, если вам нужно обновить все строки, это будет довольно дорого. Вы можете найти один из следующих вариантов:

  1. Восстановите таблицу. Массивные вставки быстрее, чем массивные обновления.
  2. Забудьте об этом. Просто JOIN при запросе таблицы для получения имени.
  3. Добавьте новую таблицу с тем же первичным ключом.
0 голосов
/ 19 февраля 2020

Вы можете использовать оператор MERGE следующим образом:

MERGE INTO CR_ARCHIVE A 
USING (
          SELECT
              MAX(B.V_SALES_PERSON) AS V_SALES_PERSON,
              B.ACCOUNT_NUM,
              B.PRODUCT_LABEL
          FROM
              TABLE_2 B
          GROUP BY
              B.ACCOUNT_NUM,
              B.PRODUCT_LABEL
      )
B ON ( A.ACCOUNT_NUM = B.ACCOUNT_NUM
       AND A.PRODUCT_LABEL = B.PRODUCT_LABEL )
WHEN MATCHED THEN 
UPDATE SET A.V_SALES_PERSON = B.V_SALES_PERSON;
/

Cheers !!

...