Как я могу приостановить и возобновить хранимую процедуру, которая обновляет каждую строку в большой таблице?
У меня есть таблица из примерно миллиона строк, и мне нужно обновить каждую строку в таблице с результатом длительного вычисления (вычисление получает потенциально различный результат для каждой строки). Поскольку это занимает много времени, DBA должен иметь возможность контролировать выполнение. Этот конкретный расчет должен выполняться один раз в год (он делает сводку по итогам года). Я хотел создать задание с помощью DBMS_SCHEDULER.CREATE_JOB, который захватит 100 строк из таблицы, обновит их, а затем остановит; следующий выполнение задания затем продолжится с того места, на котором остановилось предыдущее выполнение.
Моей первой мыслью было включить этот код в конец моей хранимой процедуры:
-- update 100 rows, storing the primary key of the last
-- updated row in last_id
-- make a new job that will run in about a minute and will
-- start from the primary key value just after last_id
dbms_scheduler.create_job
( job_name=>'yearly_summary'
, job_type=>'STORED_PROCEDURE'
, job_action=>'yearly_summary_proc(' || last_id || ')'
, start_date=>CURRENT_TIMESTAMP + 1/24/60
, enabled=>TRUE
);
Но я получаю эту ошибку, когда хранимая процедура выполняется:
ORA-27486: insufficient privileges
ORA-06512: at "SYS.DBMS_ISCHED", line 99
ORA-06512: at "SYS.DBMS_SCHEDULER", line 262
ORA-06512: at "JBUI.YEARLY_SUMMARY_PROC", line 37
ORA-06512: at line 1
Предложения о других способах сделать это приветствуются. Я бы предпочел использовать DBMS_SCHEDULER и не создавать никаких таблиц, поэтому я передаю last_id в хранимую процедуру.
3 ответов:
Я бы с осторожностью относился к использованию подобных заданий для контроля выполнения. Либо задержка между последовательными заданиями будет, как правило, слишком короткой для DBA, чтобы понять, какую работу нужно убить / приостановить / и т. д. или задержка будет достаточно длительной, чтобы значительная часть времени выполнения была потрачена на задержки между последовательными заданиями.
Не создавая никаких новых объектов, вы можете использовать пакетDBMS_ALERT , чтобы разрешить вашему DBA отправлять предупреждение, которое приостанавливает работу. Ваш код мог бы вызовите метод
DBMS_ALERT.WAITONEчерез каждые сто строк, чтобы проверить, сигнализировал ли DBA определенное предупреждение (т. е.PAUSE_YEAREND_JOBпредупреждение). Если сигнал тревоги не был получен, код можно было продолжить. Если предупреждение было получено, вы можете приостановить код либо до получения другого предупреждения (т. е.RESUME_YEAREND_JOB), либо на фиксированный период времени, либо на основе сообщения, отправленного DBA с предупреждениемPAUSE_YEAREND_JOB(т. е. сообщение может быть числом секунд для паузы или датой для паузы и т. д.)Конечно, вы могли бы сделать то же самое вещь, создав новую таблицу, имея DBA записать строку в таблицу, чтобы приостановить работу, и чтение из таблицы каждые N строк.
Еще один путь для изучения - это инструменты поддержки планировщика СУБД для окон выполнения и планов ресурсов.
Http://www.oracle-base.com/articles/10g/Scheduler10g.php
А также:
Http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14231/schedover.htm#sthref3501
С помощью windows и планов ресурсов ваш DBA может просто настроить систему на выполнение процедуры в соответствии с определенными правилами - включая окно задания и выполнение с использованием только определенного количества ресурсов (т. е. использование процессора).
Таким образом, процедура может выполняться один раз в год, и использование процессора можно контролировать.
Это, однако, не может обеспечить ручное управление, которое хотел бы получить ваш DBA.
Другой идеей было бы написать свою процедуру для обработки всех записей, но фиксировать каждую 1000 или около того. Задание СУБД.команда cancel() может использоваться вашим DBA для отмены задания, если они хотят, чтобы оно остановилось, а затем они могут возобновить его (путем изменения расписания или повторный запуск), когда они будут готовы к работе. Хитрость заключалась бы в том, что процедура должна была бы иметь возможность отслеживать обработанные строки, например, используя столбец processed_date или отдельную таблицу, содержащую первичные ключи и обработанную дату.
В дополнение к ответу о
DBMS_ALERT, ваш DBA будет признателен за возможность увидеть, где находится ваша хранимая процедура. Вы должны использоватьDBMS_APPLICATION_INFO.SET_SESSION_LONGOPSфункциональность в Oracle, чтобы сделать это.
Comments