转自:http://blog.163.com/felex_cheng@126/blog/static/41047005201110141121210/
参考资料1:
3.2 Schedules调度Programs执行的Jobs
通过schedule调度program的执行的job,看到这样的形容是不是让你彻底晕头了,就说明你还是没搞明白10g中SCHEDULERS特性管理的jobs的含意,让三思更直白地给你描述描述。10g版本中SCHEDULER将JOB分成了多个部分,program负责做什么,schedule负责啥时候做,job就简单了,一个字:做。
前面几个小节,三思已经分别演示了创建管理Jobs,创建管理Programs以及创建和管理Schedules,下面我们通过实例来演示,如何创建通过schedule调度program的执行的job吧。
首先,创建一个program,操作如下:
SQL> BEGIN
2 DBMS_SCHEDULER.CREATE_PROGRAM (
3 program_name => ¨my_program1¨,
4 program_action => ¨/bin/date¨,
5 program_type => ¨EXECUTABLE¨,
6 enabled => TRUE);
7 END;
8 /
PL/SQL procedure successfully completed.
通过上述语句,我们定义了一个program,执行操作系统命令date,并输入到dt.log文件中。
接下来定义一个schedule,操作如下:
SQL> begin
2 DBMS_SCHEDULER.CREATE_SCHEDULE (
3 schedule_name => ¨my_first_schedule¨,
4 start_date => SYSDATE,
5 repeat_interval => ¨FREQ= DAILY ; INTERVAL=1¨,
6 comments => ¨Every 1 weeks¨);
7 END;
8 /
PL/SQL procedure successfully completed.
定义调试为每周执行一次。此处repeat_interval可根据实现情况进行修改。
最后,创建job,按照指定的schedule,执行program,操作如下:
SQL> BEGIN
2 DBMS_SCHEDULER.CREATE_JOB (
3 job_name => ¨execOScmd¨,
4 program_name => ¨my_program1¨,
5 schedule_name => ¨my_first_schedule¨,
6 enabled => true);
7 END;
8 /
PL/SQL procedure successfully completed.
1.创建job
可以有两种方式来定义"计划":
1) 使用DBMS_SCHDULER.CREATE_SCHEDULE 定义一个计划;
2) 调用DBMS_SCHDULER.CREATE_JOBE过程直接指定
job_type: 目前支持三种类型:
PL/SQL块: PLSQL_BLOCK,
存储过程: STORED_PROCEDURE
外部程序: EXECUTABLE (外部程序可以是一个shell脚本,也可以是操作系统级别的指令).
job_action: 根据job_type的不同,job_action有不同的含义.
如果job_type指定的是存储过程,就需要指定存储过程的名字;
如果job_type指定的是PL/SQL块,就需要输入完整的PL/SQL代码;
如果job_type指定的外部程序,就需要输入script的名称或者操作系统的指令名
enabled: 上面已经说过了,指定job创建完毕是否自动激活
comments: 对于job的简单说明
2. 指定job的执行频率
如果我们创建了一个job,并且希望它按照我们指定的日期和时间来运行,就需要定义job的重复频度了. 例如每天运行,每周日的22:00运行, 每周一,三,五运行,每年的最后一个星期天运行等等.
(说明:10G以前的版本,与操作系统的交互方面,实现的不是很好。例如要实现一个定期的rman备份任务,就需要结合OS的命令来实现,在UNIX下可以用crontab实现,在windows下用AT命令来实现)
10G 在这方面有了很大的增强,因为创建job时可以直接指定操作系统的命令或者脚本,再合理的定义job的执行频率,可以很轻松地完成复杂的调度任务.
10G 支持两种模式的repeat_interval,一种是PL/SQL表达式,这也是dbms_job包中所使用的,例如SYSDATE 1, SYSDATE 30/24*60; 另一种就是日历表达式。
例如MON表示星期一,SUN表示星期天,DAY表示每天,WEEK表示每周等等. 下面来看几个使用日历表达式的例子:
repeat_interval => 'FREQ=HOURLY; INTERVAL=2'
每隔2小时运行一次job
repeat_interval => 'FREQ=DAILY'
每天运行一次job
repeat_interval => 'FREQ=WEEKLY; BYDAY=MON,WED,FRI"
每周的1,3,5运行job
repeat_interval => 'FREQ=YEARLY; BYMONTH=MAR,JUN,SEP,DEC; BYMONTHDAY=30'
每年的3,6,9,12月的30号运行job
用过crontab的人应该都有种似曾相识的感觉吧,呵呵
下面再说说使用日历表达式的规则:
日历表达式基本分为三部分: 第一部分是频率,也就是"FREQ"这个关键字,它是必须指定的; 第二部分是时间间隔,也就是"INTERVAL"这个关键字,取值范围是1-999. 它是可选的参数; 最后一部分是附加的参数,可用于精确地指定日期和时间,它也是可选的参数,例如下面这些值都是合法的:
BYMONTH,BYWEEKNO,BYYEARDAY,BYMONTHDAY,BYDAY
BYHOUR,BYMINUTE,BYSECOND
详细的参数说明请参考 dbms_scheduler的使用说明.
既然说到了repeat_interval,你可能要问:"有没有一种简便的方法来得出,或者说是评估出job的每次运行时间,以及下一次的运行时间呢?"
dbms_scheduler包提供了一个过程evaluate_calendar_string,可以很方便地完成这个需求.
创建job时,start_date,repeat_interval,job_action等均无须指定,因为这些参数将由program和schedule来控制。
这样,操作完成后,ORACLE就会自动定时(当前设置为每周执行一次)program中定义的操作。
虽然说jobs大多都应该是自动执行,不过经过前面的示例,大家想必也认识到了,并不是说创建了jobs它就会自动执行,是否能够真正自动执行并不是由你的主观意愿就能直接决定,而是由jobs自身的多个相关属性决定。
关于jobs自动执行的话题相信看完前面的内容后,应该都知道如何设置,下面主要演示,如何手动调用jobs并执行,这其中,当然少不了DBMS_SCHEDULER包。例如,手动执行前面刚刚创建的job:INSERT_TEST_TBL:
SQL> exec dbms_scheduler.run_job(¨INSERT_TEST_TBL¨);
PL/SQL procedure successfully completed
Jobs 每执行一次,无论成功或失败,均会在*_SCHEDULER_JOB_LOG中生成一条对应的记录(前提是LOGGING_LEVEL属性值未设置为DBMS_SCHEDULER.LOGGING_OFF),同时,用户也可以通过*_SCHEDULER_JOB_RUN_DETAILS视图查询job执行的详细信息。
停止job可以使用DMBS_SCHEDULER.STOP_JOB过程,例如:
SQL> exec dbms_scheduler.stop_job(¨INSERT_TEST_TBL¨);
PL/SQL procedure successfully completed
注意,STOP_JOB过程不仅仅是更新job的状态,而是停止当前正在执行的任务,如果你处理的任务当前未在运行的话,那么执行STOP_JOB过程,会触发ORA-27366错误。
停止Jobs也会触发一条任务的日志信息,对于执行停止操作的job,其*_SCHEDULER_JOB_LOG视图的OPERATION会记录为¨STOPPED¨,ADDITIONAL_INFO列中记录的信息类似¨REASON="Stop job called by user: username"¨。
要查看当前的执行情况,通过*_scheduler_job_run_details即可查询(*_scheduler_job_log也可以,不过该视图中信息不如detail中全面)。例如,查看刚刚创建的"EXECOSCMD"任务的执行情况,执行命令如下:
SQL> select log_id, log_date, status, additional_info
2 from user_scheduler_job_run_details
3 where job_name = ¨EXECOSCMD¨
4 ;
LOG_ID LOG_DATE STATUS ADDITIONAL_INFO
---------- -------------------- ---------- ------------------------------
13760 17-AUG-09 02.47.53.7 SUCCEEDED
34050 PM 08:00
看完这个示例之后,你是否对10g中的SCHEDULER特性多了些了解呢?千万表自满,SCHEDULER特性的功能还多着哪,接着往下看吧。
============================================================================================
只用DBMS_SCHDULER.CREATE_JOB来创建job:
grant exexcute on dbms_scheduler to u1;
grant create job,create externale job to u1;
begin
dbms_scheduler.create_job
(
job_name => 'job1',
job_type => 'EXECUTABLE',
repeat_interval => 'freq=daily;interval=1',
job_action => '/home/dbtools/move_arcs.sh',
enabled => true,
comments => 'Move Archived Logs to a Different Directory'
);
end;
/
手动执行一次: exec dbms_scheduler.run_job('job1');
exec dbms_scheduler.stop_job('job1');
删除job : exec dbms_scheduler.drop_job('job1');
查看相关表 : select * from dbms_sheduler_jobs;
select * from dbms_scheduler_job_run_details;
参考资料2:
DBMS_SCHEDULER是Oracle 10G中新增的一个包,与老版本的dbms_job包相比,dbms_scheduler有很多新特性,我将通过一系列的文章来介绍一下如何使用这个包.
1. 创建job
job是什么呢? 简单的说就是计划(schedule)加上任务说明. 另外还有一些必须的参数.
这里提到的"任务"可以是数据库内部的存储过程,匿名的PL/SQL块,也可以是操作系统级别的脚本.
可以有两种方式来定义"计划":
1) 使用DBMS_SCHDULER.CREATE_SCHEDULE 定义一个计划;
2) 调用DBMS_SCHDULER.CREATE_JOBE过程直接指定 (下面会详细说明)
在创建一个计划时,你至少需要指定下面的属性,它们是job运行所必须的:
开始时间 (start_time);
重复频率 (repeat_interval);
结束时间 (end_time)
另外,对于一个job而言,还有很多的附加参数:
job_class
job_priority
auto_drop
restartable
max_runs
max_failures
schedule_limit
logging_level
下面,我以问答的形式来具体解释.
Q1:怎么从数据库中查询job的属性 ?
A1: 有两种方法:
1) 查询(DBA|ALL|USER)_SCHEDULER_JOBS 视图
(提示: 根据用户权限的不同,选择性的查询 DBA|ALL|USER视图)
2) 调用DBMS_SCHEDULER包中的GET_ATTRIBUTE 过程
Q2: 怎么设置这些属性呢?
A2: 也是有两种方法
1) 在创建job时直接指定
2) 调用DBMS_SCHEDULER包中的SET_ATTRIBUTE 过程
Q3: "我需要什么权限才能创建job" ?
它可以创建属主为任何用户(SYS用户除外)的job.
缺省情况下,job会被创建在当前的schema下,并且是没有激活的; 如果要使job一创建
就自动激活,需要显式的设置enabled 属性为true, 来看一个例子:
begin
dbms_scheduler.create_job
(
job_name => 'ARC_MOVE',
schedule_name => 'EVERY_60_MINS',
job_type => 'EXECUTABLE',
job_action => '/home/dbtools/move_arcs.sh',
enabled => true,
comments => 'Move Archived Logs to a Different Directory'
);
end;
/
Q4: 能不能详细地讲述一下上面这个过程用到的各个参数?
A4:
job_name: 顾名思义,每个job都必须有一个的名称
schedule_name: 如果定义了计划,在这里指定计划的名称
job_type: 目前支持三种类型:
PL/SQL块: PLSQL_BLOCK,
存储过程: STORED_PROCEDURE
外部程序: EXECUTABLE (外部程序可以是一个shell脚本,也可以是操作系统级别的指令).
job_action: 根据job_type的不同,job_action有不同的含义.
如果job_type指定的是存储过程,就需要指定存储过程的名字;
如果job_type指定的是PL/SQL块,就需要输入完整的PL/SQL代码;
如果job_type指定的外部程序,就需要输入script的名称或者操作系统的指令名
enabled: 上面已经说过了,指定job创建完毕是否自动激活
comments: 对于job的简单说明
2. 指定job的执行频率
如果我们创建了一个job,并且希望它按照我们指定的日期和时间来运行,就需要定义job的重复频度了. 例如每天运行,每周日的22:00运行, 每周一,三,五运行,每年的最后一个星期天运行等等.
(说明:10G以前的版本,与操作系统的交互方面,实现的不是很好。例如要实现一个定期的rman备份任务,就需要结合OS的命令来实现,在UNIX下可以用crontab实现,在windows下用AT命令来实现)
10G 在这方面有了很大的增强,因为创建job时可以直接指定操作系统的命令或者脚本,再合理的定义job的执行频率,可以很轻松地完成复杂的调度任务.
10G 支持两种模式的repeat_interval,一种是PL/SQL表达式,这也是dbms_job包中所使用的,例如SYSDATE 1, SYSDATE 30/24*60; 另一种就是日历表达式。
例如MON表示星期一,SUN表示星期天,DAY表示每天,WEEK表示每周等等. 下面来看几个使用日历表达式的例子:
repeat_interval => 'FREQ=HOURLY; INTERVAL=2'
每隔2小时运行一次job
repeat_interval => 'FREQ=DAILY'
每天运行一次job
repeat_interval => 'FREQ=WEEKLY; BYDAY=MON,WED,FRI"
每周的1,3,5运行job
repeat_interval => 'FREQ=YEARLY; BYMONTH=MAR,JUN,SEP,DEC; BYMONTHDAY=30'
每年的3,6,9,12月的30号运行job
用过crontab的人应该都有种似曾相识的感觉吧,呵呵
下面再说说使用日历表达式的规则:
日历表达式基本分为三部分: 第一部分是频率,也就是"FREQ"这个关键字,它是必须指定的; 第二部分是时间间隔,也就是"INTERVAL"这个关键字,取值范围是1-999. 它是可选的参数; 最后一部分是附加的参数,可用于精确地指定日期和时间,它也是可选的参数,例如下面这些值都是合法的:
BYMONTH,BYWEEKNO,BYYEARDAY,BYMONTHDAY,BYDAY
BYHOUR,BYMINUTE,BYSECOND
详细的参数说明请参考 dbms_scheduler的使用说明.
转自:http://www.xifenfei.com/2230.html
1.create job
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name =>
'xifenfei_job'
,
job_type =>
'STORED_PROCEDURE'
,
job_action =>
'p_schedule'
,
repeat_interval =>
'FREQ=DAILY; BYHOUR=18,20,22'
,
enabled =>
true
,
comments =>
'XIFENFEI'
);
END
;
--每天18/20/22点执行p_schedule过程
2.disable job
BEGIN
DBMS_SCHEDULER.DISABLE(name => 'xifenfei_job');
END;
3.enable job
BEGIN
DBMS_SCHEDULER.ENABLE(name => 'xifenfei_job');
END;
4.select job
select * from USER_SCHEDULER_JOBS;
5.query logs
SELECT * FROM USER_SCHEDULER_JOB_RUN_DETAILS
WHERE job_name='XIFENFEI_JOB';
6.delete logs
--ALL_SCHEDULER_JOB_RUN_DETAILS视图
CREATE OR REPLACE VIEW ALL_SCHEDULER_JOB_RUN_DETAILS
(log_id, log_date, owner, job_name, job_subname, status, error#,
req_start_date, actual_start_date, run_duration, instance_id,
session_id, slave_pid, cpu_used, credential_owner, credential_name,
destination_owner, destination, additional_info)
AS
(SELECT
j.LOG_ID, j.LOG_DATE, e.OWNER,
DECODE(instr(e.NAME,'"'),0, e.NAME,substr(e.NAME,1,instr(e.NAME,'"')-1)),
DECODE(instr(e.NAME,'"'),0,NULL,substr(e.NAME,instr(e.NAME,'"')+1)),
e.STATUS, j.ERROR#, j.REQ_START_DATE, j.START_DATE, j.RUN_DURATION,
j.INSTANCE_ID, j.SESSION_ID, j.SLAVE_PID, j.CPU_USED,
decode(e.credential, NULL, NULL,
substr(e.credential, 1, instr(e.credential, '"')-1)),
decode(e.credential, NULL, NULL,
substr(e.credential, instr(e.credential, '"')+1,
length(e.credential) - instr(e.credential, '"'))),
decode(bitand(e.flags, 1), 0, NULL,
substr(e.destination, 1, instr(e.destination, '"')-1)),
decode(bitand(e.flags, 1), 0, e.destination,
substr(e.destination, instr(e.destination, '"')+1,
length(e.destination) - instr(e.destination, '"'))),
j.ADDITIONAL_INFO
FROM scheduler$_job_run_details j, scheduler$_event_log e
WHERE j.log_id = e.log_id
AND e.type# = 66 and e.dbid is null
AND ( e.owner = SYS_CONTEXT('USERENV','CURRENT_SCHEMA')
or /* user has object privileges */
( select jo.obj# from obj$ jo, user$ ju where
DECODE(instr(e.NAME,'"'),0, e.NAME,substr(e.NAME,1,instr(e.NAME,'"')-1))
= jo.name and e.owner = ju.name and jo.owner# = ju.user#
and jo.subname is null and jo.type# = 66
) in
( select oa.obj#
from sys.objauth$ oa
where grantee# in ( select kzsrorol from x$kzsro )
)
or /* user has system privileges */
(exists ( select null from v$enabledprivs
where priv_number = -265 /* CREATE ANY JOB */
)
and e.owner!='SYS')
)
);
--从这个视图中可以发现,日志有存在SCHEDULER$_JOB_RUN_DETAILS和
--SCHEDULER$_EVENT_LOG两张表中,所以要删除日志,就需要处理这两张表
######################删除日志操作#################
--删除SYS.SCHEDULER$_JOB_RUN_DETAILS中数据
DELETE FROM SYS.SCHEDULER$_JOB_RUN_DETAILS A
WHERE EXISTS (SELECT 1
FROM SYS.SCHEDULER$_EVENT_LOG B
WHERE B.NAME = 'XIFENFEI_JOB'
AND A.LOG_ID = B.LOG_ID);
--删除SYS.SCHEDULER$_EVENT_LOG中数据
DELETE FROM SYS.SCHEDULER$_EVENT_LOG B
WHERE B.NAME = 'XIFENFEI_JOB';
--提交
COMMIT;
#####################################################
7.delete jobs
BEGIN
DBMS_SCHEDULER.DROP_JOB(job_name => 'xifenfei_job');
END;