Обновить таблицу Oracle из другого значения таблицы в соответствующем случае - PullRequest
0 голосов
/ 28 апреля 2020

У меня есть основная таблица (скажем, tableA, в которой есть столбцы tab_a_id, field_code, field_id). Есть еще одна таблица, скажем, tableB, в которой есть столбцы area_id, area_code. tab_a_id является первичным ключом TableA. Я хочу обновить field_id таблицы A на основе field_code. field_code таблицы A и area_code таблицы B совпадают, но не идентичны, значит, field_code имеет другие значения, которые не совпадают со столбцом area_code. Я хочу установить field_id = area_id, если field_code = area_code, но, если не совпадает, следует установить значение по умолчанию -1, которое является «неизвестным» полем. Я пытался с подзапросом и массовым обновлением (например, Обновить таблицу A SET field_id = (ВЫБЕРИТЕ код зоны из таблицы B, где код зоны = код поля)). Это работало для ограниченного набора данных. Но у меня есть 3 миллиона совпадающих записей, что означает 3 миллиона подзапросов. Другая проблема в том, что существует 7 миллионов записей, в результате чего 4 миллиона непревзойденных записей и бесполезных вложенных запросов. Есть ли оптимальный способ обновления таких записей с минимальными затратами времени и большей эффективностью. Я попытался объединить команду, но она имеет низкую производительность по сравнению с l oop query

1 Ответ

1 голос
/ 01 мая 2020

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

Я создал тестовый набор в базе данных на небольшом компьютере, и самый быстрый способ получить ваши результаты - создать новая таблица (CTAS) с нужными данными и последующими именами подкачки. Я не использовал столбец первичного ключа tab_a_id для упрощения ответа.

CREATE TABLE a (field_id NUMBER, field_code VARCHAR2(30)) NOLOGGING;

CREATE TABLE b (area_id NUMBER, area_code VARCHAR2(30)) NOLOGGING;

Использование MERGE и UPDATE довольно медленно (15 минут), вероятно, из-за количества изменений:

UPDATE a SET field_id=-1 WHERE field_code NOT IN (SELECT area_code FROM b);
5,599,989 rows updated. (560 seconds)

MERGE INTO a USING b ON (a.field_code=b.area_code)
 WHEN MATCHED THEN UPDATE SET a.field_id = b.area_id;
2,400,011 rows merged. (232 seconds)

Однако создание новой таблицы с измененными данными происходит в 20 раз быстрее и занимает всего 38 секунд:

CREATE TABLE x NOLOGGING AS 
SELECT a.field_id, NVL(b.area_code, -1) AS field_code
  FROM a JOIN b ON a.field_code=b.area_code;

Вот генерация тестовых данных:

INSERT /*+ APPEND */ INTO a (field_id, field_code) SELECT id, to_char(id) from (select level as id from dual connect by rownum <= 1000000); COMMIT;
INSERT /*+ APPEND */ INTO a (field_id, field_code) SELECT field_id+1000000, to_char(field_id+1000000) from a; COMMIT;
INSERT /*+ APPEND */ INTO a (field_id, field_code) SELECT field_id+2000000, to_char(field_id+2000000) from a; COMMIT;
INSERT /*+ APPEND */ INTO a (field_id, field_code) SELECT field_id+4000000, to_char(field_id+4000000) from a; COMMIT;
EXEC dbms_stats.gather_table_stats(null, 'a');

INSERT /*+ APPEND */ INTO b (area_id, area_code) SELECT -field_id, field_code FROM a SAMPLE (30);
exec dbms_stats.gather_table_stats(null, 'b');
...