Scheduler可自动运行任务,这些任务可以是数据库中的过程,或操作系统中的命令和脚本。可以运行在本地或远程的数据库或服务器。运行可基于日程,或基于上一个任务的结果,或响应时间。Scheduler集成在资源管理中。
老的方法是使用DBMS_JOB,Enterprise Manager和操作系统也有任务调度,不过Scheduler更复杂也能力更强。
使用Oracle Scheduler简化管理任务
Scheduler包括很多对象,最基本的是job,job等级,还有程序,日程,时间窗等。
Scheduler 架构
所有Scheduler Job存于数据字典中的DBA_SCHEDULER_JOBS视图。由后台进程CJQ0调度,由Jnnn运行任务队列。最大任务队列数由JOB_QUEUE_PROCESSES决定,最大为1000,如果是0,则禁用任务调度。
SQL> show parameter JOB_QUEUE_PROCESSES
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
job_queue_processes integer 40
查看运行中的进程,以下显示只有任务调度器,而没有任务队列:
SQL> select program from v$process where program like '%J%';
PROGRAM
------------------------------------------------
oracle@oracle-19c-vagrant (CJQ0)
Job就是数据库中的过程或操作系统命令和脚本。Job的运行可基于时间(单次或重复)或事件(当满足某条件时)。Job也可以连接以形成工作流。
Scheduler可以与资源管理配合,例如使用Scheduler 激活资源管理计划(RESOURCE_MANAGER_PLAN参数或DBMS_RESOURCE_MANAGER.SWITCH_PLAN过程),例如让Job以某一优先级运行。
DBMS_SCHEDULER是管理Scheduler的API,Enterprise Manager提供图形界面。
Scheduler 对象
最基本的对象是Job。
Job
Job定义了做什么和何时做。做什么可以是存储过程,操作系统脚本,或远程的Job。何时做可以是指定时间,周期运行或基于事件。
使用DBMS_SCHEDULER.CREATE_JOB创建任务。
任务必需包括唯一的任务名,JOB_NAME。
任务类型包括:
- PLSQL_BLOCK
- STORED_PROCEDURE
- EXECUTABLE 操作系统命令
- CHAIN Job链
- EXTERNAL_SCRIPT 操作系统脚本
- SQL_SCRIPT SQL*Plus脚本
- BACKUP_SCRIPT RMAN脚本
JOB_ACTION和NUMBER_OF_ARGUMENTS定义执行的命令和参数个数。
START_DATE定义开始执行时间。
REPEAT_INTERVAL定义了重复执行周期,直到结束时间END_DATE。
JOB_CLASS定义任务优先级并与资源管理关联。
ENABLED定义任务是否可执行,默认为FALSE。
AUTO_DROP定义是否在END_DATE后删除任务定义。默认是定义后自动执行,执行后自动删除。
另一种形式的任务创建为基于事件,需指定EVENT_CONDITION参数。
Program
Program通过DBMS_SCHEDULER.CREATE_PROGRAM创建,在Job和执行的操作间建立抽象。因此可以复用。Program默认为未启用。
Schedules
通过DBMS_SCHEDULER.CREATE_SCHEDULE创建,定义何时,何周期运行任务。
开始时间默认为当前时间,结束时间默认为永远。
REPEAT_INTERVAL定义周期,包括3个元素,即频率(每秒到每年),间隔(默认为1),specifier(按秒,按年日,按月日,按周日等)。
例如:
repeat_interval=>'freq=hourly; interval=12'
表示每12小时执行一次。
repeat_interval=>'freq=yearly; bymonth=jan,mar,may;bymonthday=2'
表示每年的指定3个月的第二天运行。
repeat_interval=>'freq=weekly; interval=2; byday=mon; byhour=6;byminute=10'
表示每两周的周一6点10分运行。
简单来说,freq可以理解为单位,interval可以翻译为‘每’或every。by…可认为是指定时间。
自包含Job
使用CREATE_JOB 创建。
示例:
-- 连接到数据库
sqlplus system@orclpdb1
-- 创建一个表存放时间并设置时间格式
create table times(c1 date);
alter session set nls_date_format='dd-mm-yy hh24:mi:ss';
-- 创建任务,每一分钟插入当前时间
execute dbms_scheduler.create_job( -
job_name=>'savedate', -
job_type=>'plsql_block', -
job_action=>'insert into times values(sysdate);', -
start_date=>sysdate, -
repeat_interval=>'freq=minutely;interval=1', -
enabled=>true, -
auto_drop=>false);
-- 查询任务运行情况
SQL> select job_name, enabled, to_char(next_run_date, 'dd-mm-yy hh24:mi:ss'), run_count from user_scheduler_jobs;
JOB_NAME ENABL TO_CHAR(NEXT_RUN_ RUN_COUNT
---------- ----- ----------------- ----------
SAVEDATE TRUE 17-11-19 10:58:48 3
-- 查询任务运行情况
JOB_NAME ENABL TO_CHAR(NEXT_RUN_ RUN_COUNT
---------- ----- ----------------- ----------
SAVEDATE TRUE 17-11-19 10:59:48 4
-- 查询时间表
SQL> select * from times;
C1
-----------------
17-11-19 10:55:48
17-11-19 10:56:48
17-11-19 10:57:48
17-11-19 10:58:48
-- 禁止任务
exec dbms_scheduler.disable('savedate');
-- 查询任务状态 (ENABLED=FALSE)
SQL> select job_name, enabled, to_char(next_run_date, 'dd-mm-yy hh24:mi:ss'), run_count from user_scheduler_jobs;
JOB_NAME ENABL TO_CHAR(NEXT_RUN_ RUN_COUNT
---------- ----- ----------------- ----------
SAVEDATE FALSE 17-11-19 11:01:48 6
-- 删除任务
exec dbms_scheduler.drop_job('savedate');
-- 查询任务状态,无结果
补充,执行任务的人就是Job的创建者,如果你想让用户hr执行任务,可以赋予其创建任务的权限,然后让hr创建任务,例如:
grant create job to hr;
connect hr;
execute dbms_scheduler.create_job ...
使用 JOB CHAINS 执行系列相关任务
Job Chain是一系列有依赖关系的程序,连接的逻辑基于执行成功或失败。
以下示例创建了一个Job Chain,如果step1执行成功则执行step2,如果失败则执行step3:
exec dbms_scheduler.create_chain(chain_name=>'mychain');
exec dbms_scheduler.define_chain_step(chain_name=>'mychain', step_name=>'step1', property_name=>'prg1');
exec dbms_scheduler.define_chain_step(chain_name=>'mychain', step_name=>'step2', property_name=>'prg2');
exec dbms_scheduler.define_chain_step(chain_name=>'mychain', step_name=>'step3', property_name=>'prg3');
exec dbms_scheduler.define_chain_rule(chain_name=>'mychain', rule_name=>'rule1', condition=>'step1 succeeded', action=>'start step2');
exec dbms_scheduler.define_chain_rule(chain_name=>'mychain', rule_name=>'rule2', condition=>'step1 failed'’, action=>'start step3');
exec dbms_scheduler.enable('mychain');
运行job chain需要创建job:
exec dbms_scheduler.create_job(job_name=>'run_mychain', -
job_type=>'chain', -
job_action=>'mychain', -
start_date=>next_day(last_day(sysdate)-7, 'tuesday'), -
repeat_interval=>'freq=monthly;interval=2', -
enabled=>true);
注意,condition=>'step1 succeeded', action=>'start step2'
中的succeeded
(或者可以是completed
)和start
都是关键字,step1
和step2
与实际定义的chain step对应。
在远程系统使用Scheduler Job
可以创建远程任务,任务的定义在本地数据库,执行的脚本在远程数据库。远程主机必需安装Scheduler 代理,包含在Oracle客户端软件中,代理默认监听端口为1500.
代理和数据库之间使用HTTP协议。在创建任务时指定远端主机的网络名即可。
使用高级Scheduler特性控制Job优先级
相关组件为:
- Job Class:Job可定义Class,Class又可与资源管理中的消费组关联。
- 消费组:限制资源,如CPU等
- 资源计划:定义如何分配资源,任意时刻只能有一个生效的资源计划
- Window:时间窗内,任务可运行,或资源计划可生效
- Window Group:时间窗的组合
相同class的Job是平等的,但如果不同class的Job在同一Window内运行,资源管理会根据class对应的消费组分配资源。
使用Job Class
然后通过dbms_scheduler.set_attribute
在创建Job时或后续指定。
优先级取值1-5,默认为3,高优先级的在队列中优先执行。
日志记录也与Job Class有关,可以为不记录,仅记录执行时间和状态,完整记录等。
查询任务执行简要日志:
SQL> select job_name, log_date, status from dba_scheduler_job_log;
JOB_NAME LOG_DATE STATUS
------------------------------ ---------------------------------------- ----------------
ORA$AT_OS_OPT_SY_1 15-NOV-19 02.02.43.179531 PM +08:00 SUCCEEDED
ORA$AT_OS_OPT_SY_1 15-NOV-19 02.02.43.279176 PM +08:00
ORA$AT_OS_OPT_SY_1 15-NOV-19 02.02.43.280915 PM +08:00
ORA$AT_OS_OPT_SY_21 16-NOV-19 10.00.05.073467 PM +08:00
ORA$AT_OS_OPT_SY_21 16-NOV-19 10.00.05.089088 PM +08:00
...
详细日志可查询DBA_SCHEDULER_JOB_RUN_DETAILS
。
日志有系统任务PURGE_LOG
自动清理。每日清理30天之前的日志,由日程DAILY_PURGE_SCHEDULE
定义。
使用Windows
由dbms_scheduler.create_window
定义。
示例:
exec dbms_scheduler.create_window(-
window_name=>'daily_reporting_window', -
resource_plan=>'night_plan', -
schedule_name=>'weekday_nights', -
duration=>'0 04:00:00', -
window_priority=>'low', -
comments=>'for running regular reports');
在夜间激活资源计划night_plan,持续4小时。window_priority定义了窗口重叠时的行为。例如如果还有一个月度资源计划恰好也在夜间。当然,重叠应尽量避免。
示例:
-- SYSTEM登录系统
sqlplus system@orclpdb1
-- 查询当前window
SQL> select window_name, active from dba_scheduler_windows;
WINDOW_NAME ACTIV
-------------------- -----
MONDAY_WINDOW FALSE
TUESDAY_WINDOW FALSE
WEDNESDAY_WINDOW FALSE
THURSDAY_WINDOW FALSE
FRIDAY_WINDOW FALSE
SATURDAY_WINDOW TRUE
SUNDAY_WINDOW FALSE
WEEKNIGHT_WINDOW FALSE
WEEKEND_WINDOW FALSE
9 rows selected.
-- 查询当前生效的plan
SQL> select * from v$rsrc_plan;
-- 清除所有plan
SQL> alter system set resource_manager_plan='' scope=memory;
-- 查询plan,只剩下INTERNAL_PLAN
ID NAME IS_TO CPU INS
---------- -------------------------------- ----- --- ---
PARALLEL_SERVERS_ACTIVE PARALLEL_SERVERS_TOTAL PARALLEL_EXECUTION_MANAGED
----------------------- ---------------------- --------------------------------
CON_ID DIRECTIVE_TYPE SHARES UTILIZATION_LIMIT
---------- -------------------------------- ---------- -----------------
PARALLEL_SERVER_LIMIT MEMORY_MIN MEMORY_LIMIT PROFILE
--------------------- ---------- ------------ --------------------------------
19630 INTERNAL_PLAN TRUE ON OFF
0 16 FULL
3 DEFAULT_DIRECTIVE 200
-- 创建时间窗
execute dbms_scheduler.create_window(-
window_name=>'daytime', resource_plan=>'my_plan',-
start_date=>trunc(systimestamp) + 6/24, -
repeat_interval=>'freq=daily', -
duration=>'0 12:00:00', -
comments=>'daily at 6AM');
-- 手工开启时间窗
exec dbms_scheduler.open_window(window_name=>'daytime', duration=>'0 00:05:00', force=>true)
-- 确认
SQL> select window_name, active from dba_scheduler_windows where active='TRUE';
WINDOW_NAM ACTIV
---------- -----
DAYTIME TRUE
SQL> select * from v$rsrc_plan;
ID NAME IS_TO CPU INS
---------- -------------------------------- ----- --- ---
PARALLEL_SERVERS_ACTIVE PARALLEL_SERVERS_TOTAL PARALLEL_EXECUTION_MANAGED
----------------------- ---------------------- --------------------------------
CON_ID DIRECTIVE_TYPE SHARES UTILIZATION_LIMIT
---------- -------------------------------- ---------- -----------------
PARALLEL_SERVER_LIMIT MEMORY_MIN MEMORY_LIMIT PROFILE
--------------------- ---------- ------------ --------------------------------
73638 MY_PLAN TRUE ON OFF
0 16 FULL
3 DEFAULT_DIRECTIVE 200
-- 5分钟后,再次查询,会发现窗口已关闭并恢复为默认窗口。plan也恢复为默认。
-- 清理
exec dbms_scheduler.drop_window('daytime');
参考
- https://oracle-base.com/articles/10g/scheduler-10g
- https://oracle-base.com/articles/10g/scheduler-enhancements-10gr2#job_chains
- https://www.dummies.com/programming/databases/how-to-create-a-scheduler-job-in-oracle-12c/