Oracle 调度器(DBMS_SCHEDULER)

Oracle 调度器(DBMS_SCHEDULER)

适用版本:Oracle Database 10g / 11g / 12c / 19c / 23ai 文档版本:v1.0 / 2026-07


1. 概述

DBMS_SCHEDULER 用于调度和执行任务[1]:

优势(vs DBMS_JOB)

  • 更强大
  • 基于 PL/SQL 块、过程、脚本
  • 调度灵活
  • 事件驱动
  • 链式任务

2. 创建作业

2.1 简单作业

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'my_job',
    job_type => 'PLSQL_BLOCK',
    job_action => 'BEGIN my_proc; END;',
    start_date => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY; BYHOUR=2',
    enabled => TRUE
  );
END;
/

2.2 job_type

类型说明
PLSQL_BLOCKPL/SQL 块
STORED_PROCEDURE存储过程
EXECUTABLE外部脚本
CHAIN

2.3 repeat_interval

FREQ=YEARLY|MONTHLY|WEEKLY|DAILY|HOURLY|MINUTELY|SECONDLY
INTERVAL=N
BYHOUR=HOUR
BYMINUTE=MINUTE
BYSECOND=SECOND
BYDAY=MON|TUE|...
BYDATE=YYYYMMDD

示例:

FREQ=DAILY; BYHOUR=2                    -- 每天 2 点
FREQ=WEEKLY; BYDAY=MON,FRI              -- 每周一、五
FREQ=MONTHLY; BYMONTHDAY=1              -- 每月 1 号
FREQ=HOURLY; INTERVAL=2                 -- 每 2 小时
FREQ=MINUTELY; INTERVAL=15              -- 每 15 分钟
FREQ=DAILY; BYHOUR=9; BYMINUTE=30       -- 每天 9:30

3. 管理作业

3.1 启用/禁用

EXEC DBMS_SCHEDULER.ENABLE('my_job');
EXEC DBMS_SCHEDULER.DISABLE('my_job');

3.2 立即运行

EXEC DBMS_SCHEDULER.RUN_JOB('my_job');

3.3 停止

EXEC DBMS_SCHEDULER.STOP_JOB('my_job');

3.4 删除

EXEC DBMS_SCHEDULER.DROP_JOB('my_job');

3.5 修改

EXEC DBMS_SCHEDULER.SET_ATTRIBUTE(
  name => 'my_job',
  attribute => 'repeat_interval',
  value => 'FREQ=DAILY; BYHOUR=3'
);

4. 程序(Program)

4.1 创建程序

BEGIN
  DBMS_SCHEDULER.CREATE_PROGRAM(
    program_name => 'my_program',
    program_type => 'STORED_PROCEDURE',
    program_action => 'my_proc',
    number_of_arguments => 1,
    enabled => TRUE
  );
END;
/

4.2 定义参数

BEGIN
  DBMS_SCHEDULER.DEFINE_PROGRAM_ARGUMENT(
    program_name => 'my_program',
    argument_position => 1,
    argument_name => 'dept_id',
    argument_type => 'NUMBER',
    default_value => 10
  );
END;
/

4.3 使用程序

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'my_job',
    program_name => 'my_program',
    start_date => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY',
    enabled => TRUE
  );
END;
/

5. 调度(Schedule)

5.1 创建调度

BEGIN
  DBMS_SCHEDULER.CREATE_SCHEDULE(
    schedule_name => 'nightly_schedule',
    start_date => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY; BYHOUR=2',
    comments => 'Nightly at 2 AM'
  );
END;
/

5.2 使用调度

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'my_job',
    program_name => 'my_program',
    schedule_name => 'nightly_schedule',
    enabled => TRUE
  );
END;
/

6. 作业链(Chain)

6.1 创建链

BEGIN
  DBMS_SCHEDULER.CREATE_CHAIN(
    chain_name => 'my_chain'
  );
END;
/

6.2 定义步骤

BEGIN
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP(
    chain_name => 'my_chain',
    step_name => 'step1',
    program_name => 'program1'
  );
  
  DBMS_SCHEDULER.DEFINE_CHAIN_STEP(
    chain_name => 'my_chain',
    step_name => 'step2',
    program_name => 'program2'
  );
END;
/

6.3 定义规则

BEGIN
  DBMS_SCHEDULER.DEFINE_CHAIN_RULE(
    chain_name => 'my_chain',
    condition => 'TRUE',
    action => 'START step1'
  );
  
  DBMS_SCHEDULER.DEFINE_CHAIN_RULE(
    chain_name => 'my_chain',
    condition => 'step1 COMPLETED',
    action => 'START step2'
  );
  
  DBMS_SCHEDULER.DEFINE_CHAIN_RULE(
    chain_name => 'my_chain',
    condition => 'step2 COMPLETED',
    action => 'END'
  );
END;
/

6.4 启用链

EXEC DBMS_SCHEDULER.ENABLE('my_chain');

-- 创建链作业
BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'chain_job',
    job_type => 'CHAIN',
    job_action => 'my_chain',
    start_date => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY',
    enabled => TRUE
  );
END;
/

7. 事件驱动

7.1 创建事件队列

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'event_job',
    program_name => 'my_program',
    event_condition => 'tab.user_data.event_type = ''START_JOB''',
    queue_spec => 'my_queue',
    enabled => TRUE
  );
END;
/

8. 查看作业

8.1 作业列表

SELECT job_name, enabled, state, last_start_date, next_run_date
FROM user_scheduler_jobs;

8.2 运行历史

SELECT job_name, status, run_duration, actual_start_date
FROM user_scheduler_job_run_details
ORDER BY actual_start_date DESC;

8.3 日志

SELECT * FROM user_scheduler_job_log
ORDER BY log_date DESC;

9. 外部作业

9.1 创建

BEGIN
  DBMS_SCHEDULER.CREATE_JOB(
    job_name => 'shell_job',
    job_type => 'EXECUTABLE',
    job_action => '/u01/scripts/myscript.sh',
    start_date => SYSTIMESTAMP,
    repeat_interval => 'FREQ=DAILY; BYHOUR=2',
    enabled => TRUE
  );
END;
/

9.2 凭证

BEGIN
  DBMS_SCHEDULER.CREATE_CREDENTIAL(
    credential_name => 'my_cred',
    username => 'oracle',
    password =****** 'password'
  );
END;
/

-- 使用
EXEC DBMS_SCHEDULER.SET_ATTRIBUTE('shell_job', 'credential_name', 'my_cred');

10. 常见坑与排错

10.1 作业不运行

-- 1. 检查 enabled
SELECT job_name, enabled FROM user_scheduler_jobs;
-- 2. 检查 next_run_date
-- 3. 检查调度

10.2 ORA-27369: 外部作业失败

-- 检查脚本权限
-- 检查凭证

10.3 作业失败

-- 查看错误
SELECT job_name, status, additional_info
FROM user_scheduler_job_run_details
WHERE status = 'FAILED';

10.4 作业卡住

-- 停止
EXEC DBMS_SCHEDULER.STOP_JOB('job_name', force => TRUE);

11. 最佳实践

  1. 模块化设计:Program + Schedule + Job
  2. 复用调度:统一管理
  3. 错误处理:作业内捕获
  4. 日志记录:便于排查
  5. 链式任务:复杂流程
  6. 事件驱动:实时响应
  7. 凭证安全:外部作业
  8. 监控运行:定期检查
  9. 资源管理:避免冲突
  10. 测试充分:验证逻辑

12. 参考资料

[1] Oracle Database Administrator’s Guide 19c, “DBMS_SCHEDULER” https://docs.oracle.com/en/database/oracle/oracle-database/19/admin/scheduling-jobs.html