Использование FORALL
Если вы не можете переписать запрос для запуска одного массового обновления вместо 32k отдельных обновлений, вам все равно может повезти, если использовать PL / SQL FORALL
.Пример:
DECLARE
TYPE rec_t IS RECORD (
m_value table_2.m_value%TYPE,
m_display table_2.m_display%TYPE
);
TYPE tab_t IS TABLE OF rec_t;
data tab_t := tab_t();
BEGIN
-- Fill in data object. Replace this by whatever your logic for matching
-- m_value to m_display is
data.extend(1);
data(1).m_value := 'COL_ANC';
data(1).m_display := 'ANCHORTST';
-- Then, run the 32k updates using FORALL
FORALL i IN 1 .. data.COUNT
UPDATE table_2 t2
SET t2.m_value = data(i).m_value
WHERE EXISTS (
SELECT 1
FROM table_2 t1
WHERE trim(t1.m_display) = data(i).m_display
AND t1.m_label = t2.m_label
);
END;
/
Параллелизм
Если вы не единственный процесс в системе, обновления 32 КБ в одной транзакции могут повредить.Определенно, стоит выделить несколько тысяч строк в суб-транзакциях, чтобы уменьшить эффекты параллелизма с другими процессами, которые могут читать ту же таблицу во время обновления.
Массовое обновление
Действительно, цельлюбое улучшение должно состоять в массовом обновлении всего набора данных за один раз (или, возможно, разделении на несколько групп, см. параллелизм).
Если у вас была промежуточная таблица, содержащая инструкции по обновлению:
CREATE TABLE update_instructions (
m_value VARCHAR2(..),
m_display VARCHAR2(..)
);
Тогда вы можете выполнить что-то вроде:
MERGE INTO table_2 t2
USING (
SELECT u.*, t1.m_label
FROM update_instructions u
JOIN table_2 t1 ON trim(t1.m_display) = u.m_display
) t1
ON t2.m_label = t1.m_label
WHEN MATCHED THEN UPDATE SET t2.m_value = t1.m_value;
Это должно быть даже быстрее, чем FORALL
(но может иметь больше последствий для параллелизма).
Индексация и очистка данных
Конечно, одна вещь, которая может определенно ранить вас при выполнении 32k отдельных операторов обновления, - это функция TRIM()
, которая не позволяет эффективно использовать индекс для M_DISPLAY
.Если бы вы могли санировать свои данные, чтобы вначале не нужно было их обрезать, это определенно помогло бы.В противном случае вы можете добавить индекс на основе функций только для обновления (а затем снова удалить его):
CREATE INDEX i ON table_2 (trim (m_display));