在11g中,Oracle提供了一个新建的Scheduler特性,帮助将作业实现自动化。它还可以帮助你控制资源的利用与并可以将数据库中的作业按优先顺序执行。传统的dbms_jobs的一个限制是它只能调度基于PL/SQL的作业,不能用来调度操作系统的可执行文件或脚本。
Scheduler包括如下权限:
scheduler_admin角色包含所有的scheduler系统权限,授权如下:
SQL> grant scheduler_admin to djp01
2 /
Grant succeeded.
SQL>
manage scheduler系统权限允许做以下工作:‘
创建、删除和更改作业类,窗口和窗口组。
停止作业
提前启动和停止窗口(关于这些部件在下文中进行介绍)。
授权如下:
SQL> grant manage scheduler to djp01
2 /
Grant succeeded.
SQL>
create job系统权限允许做如下工作:
创建作业(job)、进度表(schedule)、程序(program)、链(chain)和事件(event)。
(关于这些部件在下文中会进行介绍),授权如下:
SQL> grant create job to djp01
2 /
Grant succeeded.
SQL>
如果要执行的程序在不同的模式下,那么必要拥有执行相应模式下的程序的执行权限,如下execute any procedure。
Scheduler包括如下基本部件:
(1)作业(job)
作业是一个计划执行一次或多次的任务。例子如下:
SQL> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss'
2 /
Session altered.
SQL> alter session set nls_timestamp_tz_format = 'yyyy-mm-dd hh24:mi:ss.ff'
2 /
Session altered.
SQL> alter session set nls_timestamp_format = 'yyyy-mm-dd hh24:mi:ss.ff'
2 /
Session altered.
SQL>
说明:在使用调度程序时,会涉及一些时间的相关信息,我这里进行一些时间格式的设置方便使用。
SQL> create table emp_bak
2 as
3 select *
4 from employees
5 where 1 = 0
6 /
Table created.
SQL>
SQL> begin
2 dbms_scheduler.create_job(
3 job_name=>'test_job',
4 job_type=>'PLSQL_BLOCK',
5 job_action=>'insert into emp_bak select * from employees where rownum <= 200;',
6 start_date=>'2012-12-09 14:40:00',
7 repeat_interval=>'FREQ=DAILY;INTERVAL=2',
8 end_date=>'2012-12-09 20:00:00',
9 comments=>'insert old employees into the emp_bak table',
10 auto_drop=>false,
11 enabled=>true);
12 end;
13 /
PL/SQL procedure successfully completed.
SQL>
说明:job_name指定作业的名称;job_type指定要创建的作业的类型,其值包括PLSQL_BLOCK(PL/SQL块),STORED_PROCEDURE(存储过程),EXECUTABLE(可执行文件或Java程序)。job_action指定作业要执行过程,命令或脚本。start_date与end_date指定作业的启动与结束时间。comments用于给当前作业添加注释。enabled指定创建作业时,是否启动或禁用作业,默认值为false,表示禁用;值为true,表启用。auto_drop指定该作业执行完成后,是否自动将其删除,默认值为true,表示执行完成后自动删除该作业。repeat_interval指定作业执行的频率,FREQ=DAILY;INTERVAL=2表示每天运行一次该作业。该值是一个日历表达式(calendaring expression)由三个部分组成,Frequency: 这是表达式必须包含的部分,用FREQ指定,可能取的值为YEARLY,MONTHLY,WEEKLY,DAILY,HOURLY,MINUTELY和SECONDLY。repeat interval:这个时间间隔由INTERVAL关键字标识,表示执行的频率。specific:提供一个作业何时运行的详细信息,可能取值为:BYMONTH,BYWEEKNO,BYYEARDAY,BYMONTHDAY,BYDAY,BYHOUR,BYMINUTE和BYSECOND。例如:BYMONTHDAY表示每月的某一天,BYDAY表示每周的某一天。以下是典型的日历表达式:
FREQ=DAILY;INTERVAL=3;每三天执行一次。
FREQ=HOURLY;INTERVAL=2;每隔一小时执行一次。
FREQ=WEEKLY,BYDAY=SUN;每个星期日执行一次。
FREQ=WEEKLY;INTERVAL=2,BYDAY=FRI;每隔一周的周五执行一次。
FREQ=MONTHLY;BYMONTHDAY=1;每月最后一天执行一次。
FREQ=MINUTELY;INTERVAL=30;每半个小时执行一次。
下面我们看一下执行的情况:
SQL> select count(*)
2 from emp_bak
3 /
COUNT(*)
----------
200
SQL>
上述调度程序的作业成功运行,下面我们看一些该作业的信息:
SQL> select job_style,job_type,job_action,program_name,state
2 from dba_scheduler_jobs
3 where job_name = upper('test_job')
4 /
JOB_STYLE JOB_TYPE
---------------------- --------------------------------
JOB_ACTION
--------------------------------------------------------------------------------
PROGRAM_NAME
--------------------------------------------------------------------------------
STATE
------------------------------
REGULAR PLSQL_BLOCK
insert into emp_bak select * from employees where rownum <= 200;
COMPLETED
SQL>
状态显示,该作业执行完成,该作业的类型为REGULAR(规律性的)。
作业的其他一些管理:
禁用一个作业:
SQL> exec dbms_scheduler.disable('test_job');
PL/SQL procedure successfully completed.
SQL>
激活一个作业:
SQL> exec dbms_scheduler.enable('test_job');
PL/SQL procedure successfully completed.
SQL>
运行一个作业:
SQL> truncate table emp_bak;
Table truncated.
SQL> exec dbms_scheduler.run_job('test_job');
PL/SQL procedure successfully completed.
SQL> select count(*)
2 from emp_bak
3 /
COUNT(*)
----------
200
SQL>
说明:该运行相当于是手工执行一次相应的程序。
停止一个作业:
SQL> exec dbms_scheduler.stop_job('test_job');
如果一个作业不在运行状态,它将会出现ORA-27366错误。
删除一个作业:
SQL> exec dbms_scheduler.drop_job('test_job');
PL/SQL procedure successfully completed.
SQL>
(2)进度表(schedule)
进度表是数据库执行一个作业的时间及频率的说明。假如有一些作业都是在大致相同的时间内运行的,那么,可以使用一个进度表,可以化这些作业的创建与管理。例子如下:
SQL> begin
2 dbms_scheduler.create_schedule(
3 schedule_name=>'test_schedule',
4 start_date=>systimestamp,
5 repeat_interval=>'FREQ=MINUTELY;INTERVAL=30',
6 end_date=>systimestamp+3,
7 comments=>'Every 30 minute');
8 end;
9 /
PL/SQL procedure successfully completed.
SQL>
下面我们查看该进度表的创建信息:
SQL> select start_date,end_date,schedule_type
2 from dba_scheduler_schedules
3 where schedule_name = upper('test_schedule')
4 /
START_DATE
---------------------------------------------------------------
END_DATE
---------------------------------------------------------------
SCHEDULE_TYPE
----------------
2012-12-09 17:22:43.781000
2012-12-12 17:22:43.000000
CALENDAR
SQL>
可以对已经创建的进度表进行相关属性的更改,如下:
SQL> begin
2 dbms_scheduler.set_attribute(
3 name=>'test_schedule',
4 attribute=>'start_date',
5 value=>systimestamp);
6 end;
7 /
PL/SQL procedure successfully completed.
SQL>
对已经有的进度表,我们可以进行删除,如下:
SQL> exec dbms_scheduler.drop_schedule('test_schedule');
PL/SQL procedure successfully completed.
SQL>
(3)程序(program)
程序包括关于一个scheduler作业的元数据。程序包括程序名,程序类型以及程序的动作。它是一个过程或是可执行脚本的实际名称。例子如下:
SQL> begin
2 dbms_scheduler.create_program(
3 program_name=>'test_program',
4 program_type=>'STORED_PROCEDURE',
5 program_action=>'auto_archive_emp',
6 enabled=>true,
7 comments=>'use to execute the procedure of auto_archive_emp');
8 end;
9 /
PL/SQL procedure successfully completed.
SQL>
说明:program_type与program_action同上述的job_type,job_action含义一样,这里不再说明。enabled表示该程序是否被启用,默认值为false,表示禁用。
我们可以用如下的方法对程序进行启用或禁用:
禁用一个程序:
SQL> exec dbms_scheduler.disable('test_program');
PL/SQL procedure successfully completed.
SQL>
启用一个程序:
SQL> exec dbms_scheduler.enable('test_program');
PL/SQL procedure successfully completed.
SQL>
同样,我们也可以进行删除,如下:
SQL> exec dbms_scheduler.drop_program('test_program');
PL/SQL procedure successfully completed.
SQL>
对程序相关信息的查看可以使用dba_scheduler_programs数据字典。
(4)链(chain)
可以使用调度程序链的概念将相关的程序链接在一起。因此,一个程序的成功运行,可能是以另外的程序成功运行为基础;还可以是基于一个键而非程序启动作业。链中连续的位置称为链的“步骤(step)”,每个步骤指向另一个链,程序或事件。由于链使用Oracle Streams Rules Engine(Oracle流规则引擎对象)。因此用户必须具有create job 和Rules Engine权限才能创建一个链。例子如下:
进行如下授权:
SQL> begin
2 dbms_rule_adm.grant_system_privilege(
3 dbms_rule_adm.create_rule_obj,'djp01');
4 dbms_rule_adm.grant_system_privilege(
5 dbms_rule_adm.create_rule_set_obj,'djp01');
6 dbms_rule_adm.grant_system_privilege(
7 dbms_rule_adm.create_evaluation_context_obj,'djp01');
8 end;
9 /
PL/SQL procedure successfully completed.
SQL>
创建如下:
SQL> begin
2 dbms_scheduler.create_chain(
3 chain_name=>'test_chain',
4 comments=>'A shain test');
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
定义链步骤:
SQL> begin
2 dbms_scheduler.define_chain_step(
3 chain_name=>'test_chain',
4 step_name=>'test_step1',
5 program_name=>'test_program1');
6 dbms_scheduler.define_chain_step(
7 chain_name=>'test_chain',
8 step_name=>'test_step2',
9 program_name=>'test_program2');
10 end;
11 /
PL/SQL procedure successfully completed.
SQL>
说明:链步骤可以指向一个程序、链或事件。使用不同的参数进行标识。
为了使用链有效的运行,必须给链添加规则,用于确定步骤何时运行并指定运行条件。如下:
SQL> begin
2 dbms_scheduler.define_chain_rule(
3 chain_name=>'test_chain',
4 condition=>'true',
5 action=>'start test_step1');
6 dbms_scheduler.define_chain_rule(
7 chain_name=>'test_chain',
8 condition=>'test_step1 completed',
9 action=>'start test_step2');
10 dbms_scheduler.define_chain_rule(
11 chain_name=>'test_chain',
12 condition=>'test_step2 completed',
13 action=>'end');
14 end;
15 /
PL/SQL procedure successfully completed.
SQL>
说明:在规则中,我们按照每一步的先后顺序进行定义。如果每个步骤中都事务的先后关系,使用链是一个不错的选择。
在上述步骤完成之后,我们还需要对链进行启用,如下:
SQL> exec dbms_scheduler.enable('test_chain');
PL/SQL procedure successfully completed.
SQL>
这时,我们就可以在作业(job)中使用该链了(job_type指定为chain,job_action指定对应链的名称,如test_chain)。
我们还可以使用如下方式运行:
SQL> begin
2 dbms_scheduler.run_chain(
3 chain_name=>'test_chain',
4 start_steps=>'test_step1,test_step2');
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
(5)事件(event)
Scheduler使用Oracle Stream Advanced Qeueing(Oracle流高级队列)触发事件并启动基于事件的数据库作业。事件是一个应用程序或是进程注意到某个事件或动作时发出的一条消息。有两种类型的事件:Scheduler引发的事件和应用程序引发的事件。Scheduler引发的事件由Scheduler运行中的变化而导致,比如Scheduler作业成功完成是一个事件。应用程序引发的事件由Scheduler为启动一个作业而使用或是消费。
使用基于事件的作业,只要在create_job过程上指定event_condition与queue_spec即可。但是事件的定义涉及到了,dbms_aqadm程序包的一些使用。我查看了dbms_aqadm包的声明,没有相关的注释,之后试了几次,没有达到效果,这个问题有待解决。
下面我们来看几个综合使用的例子:
SQL> begin
2 dbms_scheduler.create_job(
3 job_name=>'test_job1',
4 program_name=>'test_program1',
5 schedule_name=>'test_schedule',
6 enabled=>true,
7 auto_drop=>false,
8 comments=>'use program and schedule to create job');
9 end;
10 /
PL/SQL procedure successfully completed.
SQL>
说明:在上述作业的创建中,我使用了程序与进度表。如果要进行调整,可以调整相应的程序与进行度即可。
SQL> begin
2 dbms_scheduler.create_job(
3 job_name=>'test_job2',
4 schedule_name=>'test_schedule',
5 job_type=>'chain',
6 job_action=>'test_chain',
7 enabled=>true,
8 auto_drop=>false,
9 comments=>'use chain to create job');
10 end;
11 /
PL/SQL procedure successfully completed.
SQL>
说明:在创建job时,我们两样也可以指定一个链。如果要指定链,那么job_type为chain,job_action为所创建的链名。