如果你想每天定时在Oracle里执行一个任务,比如统计表空间增长了多少, 并且把增长状况写入另一个统计表,应该怎么来做呢?
用编程语言?如Java的Timer和TimerTask来执行定时任务。这种选择太麻烦,你还要单独去运行一个JVM让你的程序执行。能不能在Oracle内部来完成,而不需借助其他程序呢?当然可以。
Oracle提供了dbms_job这个自带package来完成定时任务的创建(提交), 修改,运行等功能。你可以把你要做的工作写在一个PL/SQL (procedure,function等)里,然后创建一个job来执行这个PL/SQL块,并给出执行初始和间隔等参数:
(1)
create or replace procedure test_pro
as
begin
insert into test_table values(sysdate);
end;
(2)
DECLARE
X NUMBER;
BEGIN
SYS.DBMS_JOB.SUBMIT
( job => X
,what => 'begin practice.test_pro; end;'
,next_date => to_date('12-03-2011 23:58:00','dd/mm/yyyy hh24:mi:ss')
,interval => 'TRUNC(SYSDATE) +1+ 23/24 + 58/1440'
,no_parse => FALSE
);
COMMIT;
END;
可以了。
其实第二步就是创建了一个匿名块,在这个块里调用了dbms_job这个package里procedure来提交任务. 后面来介绍这些参数的意义.
首先,一个job能正常运行, 对Oracle环境的配置是有要求的:
(1) 保证Oracle不在受限会话状态(restricted session)运行,
select instance_name,logins from v$instance;
如果 logins=RESTRICTED, 说明需要修改回话状态:
alter system disable restricted session;
(2) 系统参数JOB_QUEUE_PROCESSES必须大于0(不能超过1000):
查看这个参数:
show parameter job_queue_processes
修改:
alter system set job_queue_processes=20
(3) 系统参数必须为true,保证系统的触发功能可以运行:
alter system set _SYSTEM_TRIG_ENABLED=true
以下是这个package所包含的主要procedure:
submit:
PROCEDURE Submit ( job OUT binary_ineger,
What IN varchar2,
next_date IN date,
interval IN varchar2,
no_parse IN booean:=FALSE)
job,输出参数,由submit产生,它是job的标识号码。
what,需要被执行的PL/SQL代码块。
next_date,这个任务的下一次执行时间,是通过interval计算出来的。
interval,日期表达式,如果为null,则任务只执行一次。
no_parse,此工作在提交时或执行时是否应进行语法分析——TRUE指示此PL/SQL代码在它第一次执行时再进行语法分析,而FALSE指示本PL/SQL代码应立即进行语法分析。
在第一次设置任务执行时间的时候,我把任务的固定时间执行和固定间隔执行搞混了,我想这是一个容易出错的地方。如,我想我的任务在每天晚上23点50分运行,来统计当天的数据。于是next_date我给的to_date('12-03-2011 23:58:00','dd/mm/yyyy hh24:mi:ss'),而interval给的trunc(sysdate) + 1,理所当然的以为 第一次执行后时间加一天嘛,第二天照样这个时候运行. 其实不是这样的, 任务的下一次运行时间(next_date)是在任务开始时计算出来, 它的值其实是interval表达式的值,而不是通过(上一次执行时间+interval)这样的方式得出来。按照我给定的值,第一次执行的时间是正确的,但是第一次执行是算出来的第二次执行时间是 trunc(sysdate)+ 1 即第二天的零点。所以后面的时间都是错的。正确的interval值应该是'TRUNC(SYSDATE) +1+ 23/24 + 58/1440',这样算出来才是第二天的晚上23点58分。关于任务的时间,可以参看:http://blog.youkuaiyun.com/li_guang/archive/2008/06/04/2510846.aspx
remove
PROCEDURE Remove(job IN binary_ineger);
将一个job从任务队列里删除,参数:job的标识
next_date
PROCEDURE Next_Date(job IN binary_ineger,
next_date IN date)
手动设置任务的下一次运行时间
Interval
PROCEDURE Interval (job IN binary_integer,
设置任务执行时间的计算方法.
Change
PROCEDURE Change (job IN binary_integer,
What IN varchar2,
next_date IN date,
interval IN varchar2)
修改一个任务
Broken
PROCEDURE Broken (job IN binary_integer,
Broken IN boolean,
next_date IN date :=SYSDATE)
修改任务的状态, true为可运行,false不可.
run
PROCEDURE run(job IN binary_ineger);
立即运行一个任务
javaeye的这个文章编辑器太让人蛋疼了, 插入的代码格式全没了,我曰,辛辛苦苦写了这么久