Я столкнулся с миграцией данных, моя цель - обновить 2,5 млн строк менее чем за 8 часов, потому что у клиента есть ограниченное время, в течение которого услугу можно отключить. Более того, таблица не может быть заблокирована во время этого выполнения, потому что она используется другими процедурами, я могу заблокировать только запись. Выполнение будет осуществляться в пакетном режиме. Вероятно, в этом случае миграция - неправильное слово, лучше сказать «изменение данных» ...
Система: Oracle 11g
Информация о таблице
Имя таблицы: Tab1 Всего строк: 520,000,000 Средняя длина строки: 57
DESC Tab1;
Name Null? Type
---------------- -------- -----------
t_id NOT NULL NUMBER
t_fk1_id NUMBER
t_fk2_id NUMBER
t_start_date NOT NULL DATE
t_end_date DATE
t_del_flag NOT NULL NUMBER(1)
t_flag1 NOT NULL NUMBER(1)
f_falg2 NOT NULL NUMBER(1)
t_creation_date DATE
t_creation_user NUMBER(10)
t_last_update DATE
t_user_update NUMBER(10)
t_flag3 NUMBER(1)
Индексы:
T_ID_PK [t_id] UNIQUE
T_IN_1 [t_fk2_id,t_fk1_id,t_start_date,t_del_flag] NONUNIQUE
T_IN_2 [t_last_update,t_fk2_id] NONUNIQUE
T_IN_3 [t_fk2_id,t_fk1_id] NONUNIQUE
В настоящее время я подумал о некоторых возможных решениях, и большую часть из них я уже тестировал :
- Вставить + удалить: выбрать существующие данные, вставить новую запись с необходимыми изменениями и удалить старую [этот результат как самый медленный метод ~ 21 час]
- Слияние: используйте команда merge для обновления существующих данных [этот результат как самый быстрый метод ~ 16 часов]
- Обновление: обновить существующие данные [~ 18 часов]
С указанным выше решением я столкнулся некоторые проблемы, такие как: при выполнении с параметром / * + parallel (x) / таблица была заблокирована, / + RESULT_CACHE * /, похоже, не влияет на выбор вообще время. Моя последняя идея - разделить таблицу на новый столбец и использовать его, чтобы избежать блокировки таблицы и перейти к решению 1.
Здесь запрос, используемый для параметра слияния (для двух других одинаковый больше или меньше):
DECLARE
v_recordset NUMBER;
v_row_count NUMBER;
v_start_subset NUMBER;
v_tot_loops NUMBER;
BEGIN
--set the values manually for example purpose, I've use the same values
v_recordset := 10000;
v_tot_loops := 10000;
BEGIN
SELECT NVL(MIN(MOD(m_id,v_recordset)), 99999)
INTO v_start_subset
FROM MIGRATION_TABLE
WHERE m_status = 0; -- 0=not migrated , 1=migrated
END;
FOR v_n_subset IN v_start_subset..v_tot_loops
LOOP
BEGIN
MERGE INTO Tab1 T1
USING (
SELECT m.m_new_id, c2.c_id, t.t_id
FROM MIGRATION_TABLE m
JOIN Tab1 t ON t.t_fk_id = m.m_old_id
JOIN ChildTable c ON c.c_id = t.t_fk2_id
JOIN ChildTable c2 ON c.c_name = c2.c_name --c_name is an UNIQUE index of ChildTable
WHERE MOD(m.m_id,v_recordset) = v_n_subset
AND c.c_fk_id = old_product_id --value obtained from another subsystem
AND c2.c_fk_id = new_product_id --value obtained from another subsystem
AND t.t_del_flag = 0 --not deleted items
) T2
ON (T1.t_id = T2.t_id)
WHEN MATCHED THEN
UPDATE T1.t_fk_id = T2.m_new_id, T1.t_fk2_id = T2.c_id, T1.t_last_update = trunc(sysdate)
;
--Update the record as migrated and proceed
COMMIT;
EXCEPTION WHEN OTHERS THEN
ROLLBACK;
END;
END LOOP;
END;
В приведенном выше скрипте я удалил параметры параллельности и кеширования, но я уже тестировал их с обоими и не получил никаких результатов об ошибке.
Кто угодно, пожалуйста! Не могли бы вы помочь мне с этим, более чем за неделю я не смог достичь желаемого времени, какие-либо идеи?
MIGRATION_TABLE
CREATE TABLE MIGRATION_TABLE(
m_customer_from VARCHAR2(5 BYTE),
m_customer_to VARCHAR2(5 BYTE),
m_old_id NUMBER(10,0) NOT NULL,
m_new_id NUMBER(10,0) NOT NULL,
m_status VARCHAR2(100 BYTE),
CONSTRAINT M_MIG_PK_1
(
m_old_id
)
ENABLE
)
CREATE UNIQUE INDEX M_MIG_PK_1 ON MIGRATION_TABLE (m_old_id ASC)
ChildTable
CREATE TABLE ChildTable(
c_id NUMBER(10, 0) NOTE NULL,
c_fk_id NUMBER(10, 0),
c_name VARCHAR2(100 BYTE),
c_date DATE,
c_note VARCHAR2(100 BYTE),
CONSTRAINT C_CT_PK_1
(
c_id
)
ENABLE
)
CREATE UNIQUE INDEX C_CT_PK_1 ON ChildTable (c_id ASC)
CREATE UNIQUE INDEX C_CT_PK_2 ON ChildTable (c_name ASC, c_fk_id ASC)