Запрос UPDATE выполняется медленно в сочетании с предложением RETURNING INTO - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть запрос на обновление, который возвращает обновленный идентификатор строки.Время выполнения запроса составляет около 90 секунд.Когда я удаляю предложение Returning, тогда время выполнения составляет 1 мс.Таблица update_table содержит 39000 строк.Запрос обновляет 0 строк в этом случае.При обновлении 3 строки - время выполнения одинаково.

DECLARE
  type intTable IS TABLE OF INTEGER;
  idCol intTable;
BEGIN
UPDATE 
  update_table
            SET  
            prop1 = 3, prop2 = NULL
            WHERE EXISTS (
                SELECT null FROM update_table f 
                    INNER JOIN rel_table1 u ON f.ID= u.ID
                    INNER JOIN rel_table2 VP ON f.another_ID = VP.another_ID
                WHERE (u.prop1 = 3) 
                    AND VP.prop1 = 1
                    AND (u.prop2 = 75)
                    AND f.ID = update_table.ID
            )
         ReTURNING ID BULK COLLECT INTO idCol;
.
.
.
  END;

Почему возврат предложения замедляет запрос?

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Хорошая часть использования Oracle - это знание того, что «должно» произойти, а что нет.

Добавление условия RETURNING INTO не «подразумевает» замедление работы вашего обновления.Когда происходит что-то, чего не должно быть, зайдите на сайт поддержки Oracle, чтобы узнать, является ли это известной ошибкой.

В вашем случае похоже, что вы столкнулись с:

Ошибка 27131648 - ПОД ОПТИМАЛЬНЫЙ ПЛАН ОБ ОБНОВЛЕНИИ ОБНОВЛЕНИЯ С ВОЗВРАТОМ В

Я не уверен, есть ли патч, но есть простой обходной путь: используйте подсказку UNNEST.В вашем случае это будет:

UPDATE 
  update_table
            SET  
            prop1 = 3, prop2 = NULL
            WHERE EXISTS (
                SELECT /*+ UNNEST */ null FROM update_table f 
                    INNER JOIN rel_table1 u ON f.ID= u.ID
                    INNER JOIN rel_table2 VP ON f.another_ID = VP.another_ID
                WHERE (u.prop1 = 3) 
                    AND VP.prop1 = 1
                    AND (u.prop2 = 75)
                    AND f.ID = update_table.ID
            )
         ReTURNING ID BULK COLLECT INTO idCol;
0 голосов
/ 08 февраля 2019

Я бы порекомендовал разделить его на две части: первую BULK COLLECT и следующую FORALL собранных идентификаторов, причем обе чрезвычайно быстро, и вы сможете продолжать ссылаться на обновленные идентификаторы с idCol.

DECLARE
  type intTable IS TABLE OF INTEGER;
  idCol intTable;
BEGIN
    SELECT f.id 
      BULK COLLECT INTO idCol
      FROM update_table f 
     INNER JOIN rel_table1 u ON f.ID= u.ID
     INNER JOIN rel_table2 VP ON f.another_ID = VP.another_ID
     WHERE (u.prop1 = 3) 
         AND VP.prop1 = 1
         AND (u.prop2 = 75);

    FORALL indx IN 1..idCol.COUNT
        UPDATE update_table
           SET prop1 = 3, prop2 = NULL
         WHERE id = idCol(indx);

.
.
.
END;

Надеюсь, я помог!

...