Если ваше требование состоит в том, чтобы ваши коммиты не превышали 10 000 записей на коммит (но коммитам по-прежнему разрешается быть меньше, чем 10 000 записей на коммит), то вам повезло.
Вам не нужно управлять своим собственным размером коммита или вообще ставить в очередь.
Oracle имеет встроенные утилиты для такого рода вещей.
Ниже я добавлю пример обработки блока 10K самостоятельно, но простое использование встроенных функций Oracle сэкономит время и позволит избежать ошибок.
Вот пример, в котором используется DBMS_PARALLEL_EXECUTE
(вы можете установить степень параллельности на 1, если вы на самом деле не хотите много распараллеливать).
Примечательными элементами здесь являются CHUNK_SIZE => 10000
для ограничения размера коммита, PARALLEL_LEVEL => 1
для ограничения параллели и ROWID BETWEEN :STARD_ID AND :END_ID
(также ROWNUM
был удален, но остальная часть вашего оригиналазапрос был оставлен как есть, включая элементы ID IS NOT NULL
и ID IN
)
BEGIN
DBMS_PARALLEL_EXECUTE.CREATE_TASK(TASK_NAME => 'NULL_CONTRACT_TYPE');
DBMS_PARALLEL_EXECUTE.CREATE_CHUNKS_BY_ROWID(
TASK_NAME => 'NULL_CONTRACT_TYPE' ,
TABLE_OWNER => 'BILLING',
TABLE_NAME => 'ACCOUNT_COUNTRY',
BY_ROW => TRUE,
CHUNK_SIZE => 10000);
DBMS_PARALLEL_EXECUTE.RUN_TASK(
TASK_NAME => 'NULL_CONTRACT_TYPE' ,
SQL_STMT => 'UPDATE account_country SET contract_type_id = NULL ' ||
'WHERE mdate < SYSDATE - 300 ' ||
'AND mdate >= SYSDATE - 500 ' ||
'AND id IS NOT NULL AND id IN ( 209 ) ' ||
'AND contract_type_id < 1000 ' ||
'AND ROWID BETWEEN :START_ID AND :END_ID',
LANGUAGE_FLAG => DBMS_SQL.NATIVE,
PARALLEL_LEVEL => 1);
DBMS_PARALLEL_EXECUTE.DROP_TASK(TASK_NAME => 'NULL_CONTRACT_TYPE');
END;
/
Затем Oracle сделает все остальное за вас - фиксация в указанных блоках, обновление только целевых записейи т. д.
Но, если вы все еще хотите сделать это самостоятельно, один из подходов - извлечь из курсора и ограничить количество целевых строк.Ниже приведен пример этого (как и раньше, я оставил ваш исходный запрос без изменений).Из вашего исходного запроса может показаться, что ID не уникален, поэтому я использую ROWID
s для этого примера.
DECLARE
TYPE ROWID_LIST IS TABLE OF ROWID;
V_UPDATE_TARGETS ROWID_LIST := ROWID_LIST();
CURSOR UPDATE_ACCOUNT_COUNTRY_TARGETS IS (
SELECT ROWID FROM ACCOUNT_COUNTRY
WHERE mdate < SYSDATE - 300
AND mdate >= SYSDATE - 500
AND id IS NOT NULL AND id IN ( 209 )
AND contract_type_id < 1000);
BEGIN
OPEN UPDATE_ACCOUNT_COUNTRY_TARGETS;
LOOP
EXIT WHEN UPDATE_ACCOUNT_COUNTRY_TARGETS%NOTFOUND;
FETCH UPDATE_ACCOUNT_COUNTRY_TARGETS BULK COLLECT INTO V_UPDATE_TARGETS LIMIT 10000;
FORALL ROWID_INDEX IN 1..V_UPDATE_TARGETS.COUNT
UPDATE ACCOUNT_COUNTRY
SET CONTRACT_TYPE_ID = NULL
WHERE ROWID = V_UPDATE_TARGETS(ROWID_INDEX);
COMMIT;
END LOOP;
CLOSE UPDATE_ACCOUNT_COUNTRY_TARGETS;
END;
/