【OCP学习记录一】【Oracle10g参考】 DBMS_SCHEDULER

【题目】

23. While creating a job class using the DBMS_SCHEDULER package, you set the logging level to LOGGING_RUNS. What would be the impact of this setting?

A. Oracle Scheduler would write detailed information to the job log for each run of each job in the job class.

B. Oracle Scheduler would write detailed information to the job log for the first run of each job in the job class.

C. Oracle Scheduler would write detailed information to the job log for each run of only the first job in the job class.

D. Oracle Scheduler would write detailed information for all operations performed on all jobs in the job class.

Answer: A

            【参考】

在10g环境中,ORACLE建议使用Scheduler替换普通的job,来管理任务的执行。其实,将Scheduler描述成管理job的工具已经太过片面了,10G版本中新增的Scheduler绝不仅仅是创建任务这么简单。。。。

  • 提示:ORACLE中管理Scheduler是通过DBMS_SCHEDULER包,本章也以此为切入点,通过详细介绍DBMS_SCHEDULER包的使用,来演示如何使用Scheduler。似乎本末倒置了,没关系,"三思笔记",俺的地盘俺做主。

一、使用Jobs

  所谓JOBS,其实就是Scheduler管理的一个(或多个)任务的执行调度。

1.1  创建Jobs

  通过DBMS_SCHEDULER包来创建Jobs,是使用其CREATE_JOB过程。在创建Job时,用户可以指定要执行的任务,调度信息(啥时候执行,执行周期,终止日期等)以及其它一些任务相关的属性。CREATE_JOB过程调用还是比较简单的,例如:

 BEGIN

  DBMS_SCHEDULER.CREATE_JOB (

 job_name           =>  'INSERT_TEST_TBL',

 job_type           =>  'STORED_PROCEDURE',

 job_action         =>  ' P_ INSERT INTOTEST ',

start_date         =>  sysdate,

repeat_interval    =>  'FREQ=DAILY;INTERVAL=1');

END;

 /

  • PL/SQL  过程已成功完成。

  事实上,有权限的话,用户也可以创建其它SCHEMA下的JOB,只需要在指定JOB_NAME时,按照schema.job_name的格式即可。注意哟,这种情况下创建的JOB,其CREATED与OWNER有可能并不相同的哟。

  当使用CREATE_JOB过程创建JOB时,可指定的参数值很多,只不过多数情况下用户仅指定部分参数即可满足需求。

  其中,上例中指定的参数,分别代表的含义如下:

    • JOB_NAME :指定任务的名称,必选值,注意要确保指定的名称唯一。
    • JOB_TYPE :任务执行的操作类型,必选值,有下列几个可选值:
      • PLSQL_BLOCK :表示任务执行的是一个PL/SQL匿名块。
      • STORED_PROCEDURE :表示任务执行的是ORACLE过程(含PL/SQL PROCEDURE和JAVA PROCEDURE),本例中正是指定这一参数值。
      • EXECUTABLE :表示任务执行的是一个外部程序,比如说操作系统命令。
      • CHAIN :表示任务执行的是一个CHAIN。
    • JOB_ACTION :任务执行的操作,必选值,应与JOB_TYPE类型中指定的参数相匹配。

比如说对于PL/SQL匿名块,此处就可以放置PL/SQL块的具体代表,类似DECLARE .. BEGIN ..END这类;

如果是ORACLE过程,那么此处应该指定具体的过程名,注意由于任务执行,即使过程中有OUT之类参数,实际执行时也不会有输出的。

    • START_DATE :指定任务初次执行的时间,本参数可为空,当为空时,表示任务立刻执行,效果等同于指定该参数值为SYSDATE。
    • REPEAT_INTERVAL :指定任务执行的频率,比如多长时间会被触发再次执行。
    • 本参数也可以为空,如果为空的话,就表示当前设定的任务只执行一次。
    • REPEAT_INTERVAL参数需要好好说说,因为这一参数与标准JOB中的INTERVAL参数有很大区别,相比之下,REPEAT_INTERVAL参数的语法结构要复杂的多。其中最重要的是FREQ和INTERVAL两个关键字。
      • FREQ 关键字用来指定间隔的时间周期,可选参数有:YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, and SECONDLY,分别表示年、月、周、日、时、分、秒等单位。
      • INTERVAL 关键字用来指定间隔的频繁,可指定的值的范围从1-99。

例如:REPEAT_INTERVAL=>'FREQ=DAILY;INTERVAL=1';表示每天执行一次,如果将INTERVAL改为7就表示每7天执行一次,效果等同于FREQ=WEEKLY;INTERVAL=1。

一般来说,使用DBMS_SCHEDULER.CREATE_JOB创建一个JOB,至少需要指定上述参数中的前3项。除此之外,还可以在CREATE_JOB时,指定下列参数:

    • NUMBER_OF_ARGUMENTS :指定该JOB执行时需要附带的参数的数量,默认值为0,注意当JOB_TYPE列值为PLSQL_BLOCK或CHAIN时,本参数必须设置为0,因为上述两种情况下不支持附带参数。
    • END_DATE :指定任务的过期时间,默认值为NULL。任务过期后,任务的STATE将自动被修改为COMPLETED,ENABLED被置为FALSE。如果该参数设置为空的话,表示该任务永不过期,将一直按照REPEAT_INTERVAL参数设置的周期重复执行,直到达到设置的MAX_RUNS或MAX_FAILURES值。
    • JOB_CLASS :指定任务关联的CLASS,默认值为DEFAULT_JOB_CLASS。关于JOB CLASS的信息就关注本系列的后续文章。
    • ENABLED :指定任务是否启用,默认值为FALSE。FALSE状态表示该任务并不会被执行,除非被用户手动调用,或者用户将该任务的状态修改为TRUE。
    • AUTO_DROP :当该标志被置为TRUE时,ORACLE会在满足条件时自动删除创建的任务
      • 任务已过期;
      • 任务最大运行次数已达MAX_RUNS的设置值;
      • 任务未指定REPEAT_INTERVAL参数,仅运行一次;

该参数的默认值即为TRUE。用户在执行CREATE_JOB过程时可以手动将该标志指定为FALSE,当参数值设置为FALSE时,即使满足上述提到的条件任务也不会被自动删除,这种情况下,唯一能够导致任务被删除的情况,就是用户主动调用DROP_JOB过程。

  • COMMENTS :设置任务的注释信息,默认值为NULL。

  上面的例子创建了一个新的JOB,不过这个JOB与普通JOB不同哟,此时查询USER_JOBS视图是查不到刚刚创建的JOB的信息,因为这个JOB是SCHEDULER管理的JOB。要查询SCHEDULER管理的JOS,应该通过USER_SCHEDULER_JOBS(当然ALL_SCHEDULER_JOBS和DBA_SCHEDULER_JOBS也可以),例如:

SQL> select job_name,job_type,job_action,to_char(start_date,'yyyy-mm-dd hh24:mi:ss'),repeat_interval,enabled,state from user_scheduler_jobs;

JOB_NAME             JOB_TYPE         JOB_ACTION                TO_CHAR(START_DATE, REPEAT_INTERVAL                ENABL STATE

-------------------- ---------------- ------------------------- ------------------- ------------------------------ ----- ---------------

  • INSERT_TEST_TBL      STORED_PROCEDURE P_INSERTINTOTEST          2009-07-27 13:46:50 FREQ=DAILY;INTERVAL=1          FALSE DISABLED

  不过,细心的盆友可能会发现,JOB虽然成功创建了,但却并未执行,这是怎么回事?其实原因很简单,还记的前面介绍CREATE_JOB过程时提到的ENABLED参数吗,当不显式指定时,该参数的默认值为false,JOB自然不会运行了。如果遇到这类情形,如何修改呢?请继续关注下一节

1.2  管理Jobs

1.2.1  启用Jobs

  前面创建JOB时,由于未显式的指定ENABLED参数,因此即使指定了START_DATE,不过默认情况下JOB不会自动执行。对于这种情况,DBMS_SCHEDULER包中提供了一个过程ENABLE,可以用来修改JOB的启用状态,调用方式非常简单,例如:

SQL> exec dbms_scheduler.enable(¨INSERT_TEST_TBL¨);

  • PL/SQL procedure successfully completed.

1.2.2  禁用Jobs

  DBMS_SCHEDULER.ENABLE 仅用来将JOB(其实不仅仅对JOB有效,对于CHAIN、PROGRAM等也有效)的启用状态置为TRUE。如果想将其启用状态置为FALSE?简单,还有一个与该功能对应的过程:DBMS_SCHEDULER.DISABLE,例如:

SQL> exec dbms_scheduler.disable(¨INSERT_TEST_TBL¨);

  • PL/SQL procedure successfully completed.

  这两个过程仅用来重置对象的状态,因此均可以无限次执行,即使执行时对象已经被置为要指定的状态。

1.2.3  修改Jobs

  由于JOB的属性众多,难免时不时的可能会遇到需要修改的情况,比如说前面创建JOB时不小心,指定要执行的过程名输入错误(完全有可能,CREATE_JOB在创建时不会自动检查指定的过程是否有效,从这方面考虑,SCHEDULER不如普通JOB严谨哪),这种情况下就必然涉及到对JOB的修改(或者说重定义),没问题,DBMS_SCHEDULER包中专门提供了一个过程SET_ATTRIBUTE,可以用来修改任务的属性值。

  例如,修改刚刚创建的JOB:INSERT_TEST_TBL执行的过程,执行语句如下:

SQL> exec dbms_scheduler.set_attribute(¨INSERT_TEST_TBL¨,¨JOB_ACTION¨,¨P_ INSERT INTOTEST¨);

  • PL/SQL procedure successfully completed

  当然啦,我们这里执行的这条语句,执行跟没执行没有区别,此处仅做示例,大家表深究。

  SET_ATTRIBUTE 过程虽然仅有三个参数,不过能够修改的属性值可是不少,以下列举几个较常用到的:

    • LOGGING_LEVEL :指定对jobs执行情况记录的日志信息级别。

SCHEDULER 管理的JOB对任务的执行情况专门进行了记录,同时用户还可以选择日志中记录信息的级别,有下列三种选择:

    • DBMS_SCHEDULER.LOGGING_OFF :关闭日志记录功能;
    • DBMS_SCHEDULER.LOGGING_RUNS :对任务的运行信息进行记录;
    • DBMS_SCHEDULER.LOGGING_FULL :记录任务所有相关信息,不仅有任务的运行情况,甚至连任务的创建、修改等也均将记入日志。

提示:查看SCHEDULER管理的JOB,可以通过USER_SCHEDULER_JOB_LOG和USER_SCHEDULER_JOB_RUN_DETAILS两个视图中查询

    • RESTARTABLE :指定jobs运行出错后,是否能够适时重启

创建任务时如未明确指定,本参数默认情况下设置为FALSE,如果设置为TRUE,就表示当任务运行时出错,下次运行时间点到达时仍会启动,并且如果运行仍然出错,会继续重新运行,不过如果连接出错达到6次,该job就会停止。

    • MAX_FAILURES :指定jobs最大连续出错次数

该参数值可指定的范围从1-1000000,默认情况下该参数设置为NULL,表示无限制。达到指定出错次数后,该job会被自动disable。

    • MAX_RUNS :指定jobs最大运行次数

该参数值可指定的范围从1-1000000,默认情况下该参数设置为NULL,表示无限制(只是运行次数无限制,实际job会否继续运行,仍受制于end_date以及max_failures等参数的设置)。达到指定运行次数后,该job也将被自动disable,并且状态会被置为COMPLETED。

    • JOB_TYPE :指定job执行的任务的类型

有四个可选值:¨PLSQL_BLOCK¨, ¨STORED_PROCEDURE¨, ¨EXECUTABLE¨, and ¨CHAIN¨。

    • JOB_ACTION :指定job执行的任务

这一参数所指定的值依赖于JOB_TYPE参数中的值,比如说JOB_TYPE设置为¨STORED_PROCEDURE¨,那么本参数值中指定的一定是ORACLE中的过程名。

  • START_DATE :指定job初次启动的时间
  • END_DATE :指定job停止运行的时间

  本参数又与AUTO_DROP相关联,如果AUTO_DROP设置为TRUE的话,那么一旦job到达停止运行的时间,该job就会被自动删除,否则的话job任何存在,不过状态被修改为COMPLETED。

  除此之外,其它还包括MAX_RUN_DURATION,JOB_WEIGHT,INSTANCE_STICKINESS,STOP_ON_WINDOW_CLOSE,JOB_PRIORITY,SCHEDULE_LIMIT,PROGRAM_NAME,NUMBER_OF_ARGUMENTS,SCHEDULE_NAME,REPEAT_INTERVAL,JOB_CLASS,COMMENTS,AUTO_DROP,EVENT_SPEC,RAISE_EVENTS等等,这些参数所代表的意义此处不一一详述,感兴趣的朋友可以查阅相关官方文档,或者等待本系列文章的外传,黑黑。

  仅从这些可设置属性就可以看出,Scheduler管理的job确实非常灵活,上述提到了这些参数,均可以使用DBMS_SCHEDULER.SET_ATTRIBUTE过程进行设置。

  另外需要注意一点,除了用户手动创建的jobs之外,数据库在运行过程中也有可能自动创建jobs。对于这类jobs除非必要,否则不建议进行修改。至于如何区分jobs是用户创建,还是数据库自动创建,可以通过*_SCHEDULER_JOBS视图的SYSTEM列来确定,如果该列显示为TRUE,则表示由系统创建

1.2.4  执行Jobs

  虽然说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执行的详细信息。

1.2.5  停止Jobs

  停止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"¨。

1.2.6  删除Jobs

  删除创建的job就比较简单了,直接执行DBMS_SCHEDULER.DROP_JOB过程即可,例如:

SQL> exec dbms_scheduler.drop_job(¨INSERT_TEST_TBL¨);

  • PL/SQL procedure successfully completed

  删除jobs并不是修改该job中某个字段的标记值,而是直接删除其在数据字典中的字义,因此被删除的job如果未来发现仍然需要,只能重建,而无法通过其它方式快速恢复。不过,删除jobs的操作,并不会级联删除这些job曾经执行过的日志信息。

二、使用Programs

  在论坛中偶尔见过有人讨论如何在ORACLE中执行操作系统命令,或是ORACLE数据库外的应用。应该说在9i及之前的版本中,虽然说并非完全无法实现(其实还是有多种方式能够变相实现的),不过复杂的实现方式让DBA使劲了力,伤透了心,费劲了事儿。

  进入10g版本之后,就完全不必如此费神,因为有了DBMS_SCHEDULER,因为有了PROGRAM。

2.1  创建Programs

  Scheduler 中的Program对象并不是常规意义上的"程序"或"应用",而就是一个"对象",由DBA定义的,具有执行某项功能的特殊对象。Program中实际执行的操作可以分为下列三种类型:

  • PL/SQL BLOCK :标准的pl/sql代码块;
  • STORED PROCEDURE :编译好的PL/SQL存储过程,或者Java存储过程,以及外部的c子程序;
  • EXECUTEABLE :ORACLE数据库之外的应用,比如操作系统命令等等。

  创建Programs使用DBMS_SCHEDULER.CREATE_PROGRAM过程,该过程支持的参数如下:

JSSWEB>  desc dbms_scheduler.create_program;

Parameter           Type           Mode Default? 

------------------- -------------- ---- -------- 

PROGRAM_NAME        VARCHAR2       IN            

PROGRAM_TYPE        VARCHAR2       IN            

PROGRAM_ACTION      VARCHAR2       IN            

NUMBER_OF_ARGUMENTS BINARY_INTEGER IN   Y        

ENABLED             BOOLEAN        IN   Y        

  • OMMENTS            VARCHAR2       IN   Y      

  如上所示,前三项为必选参数,各参数实际代表的意义如下:

  • PROGRAM_NAME :指定一个program名称;
  • PROGRAM_TYPE :Program的类型,如前文中所述,Program支持三种类型;
  • PROGRAM_ACTION :实际执行的操作,应与前面PROGRAM_TYPE参数关联使用。
  • 比如说前面指定了PROGRAM_TYPE为"PLSQL_BLOCK",那么此处要执行的action就应当是一段标准的pl/sql代码。
  • 如果前面指定PROGRAM_TYPE为"STORED_PROCEDURE",那么此处要执行的action就应当是ORACLE中定义好的存储过程(含Java存储过程),
  • 如果前面指定PROGRAM_TYPE为"EXECUTABLE",那么此处就应该指定外部命令的命令行信息(含路径信息);
  • NUMBER_OF_ARGUMENTS :指定支持的参数个数,默认值为0即没有参数。每个program最多能够支持255个参数,注意如果PROGRAM_TYPE设置为PLSQL_BLOCK,那么本参数自动忽略;
  • ENABLED :指定是否将创建的program置为有效状态,默认情况下为false。
  • COMMENTS :这个不用再说了吧,注释信息。

  下面实际操作一下看看,PL/SQL或PROCEDURE没有挑战(ORACLE中直接即可调用),咱们创建一下program,直接调用操作系统中的ls命令,操作如下:

 BEGIN
  DBMS_SCHEDULER.CREATE_PROGRAM (
     program_name           => 'my_program1',
      program_action         => '/bin/date',
     program_type           => 'EXECUTABLE',
    enabled                => TRUE);
  END;
   /

  • PL/SQL procedure successfully completed.

2.2  管理Programs

  定义的program如何执行,这里先卖个关子,前面介绍CREATE_PROGRAM过程的参数时提到,每个program最多支持255个参数,要为program添加参数,可以通过DEFINE_PROGRAM_ARGUMENT过程。不过在为其添加参数前,要注意program的NUMBER_OF_ARGUMENTS指定的数量,如果该值为0,那么为其添加参数时就会报错。

  查询创建的program的信息,可以通过USER_SCHEDULER_PROGRAMS视图,例如:

SQL> select program_name,program_type,program_action,number_of_arguments,enabled

  2  from user_scheduler_programs;

PROGRAM_NAME         PROGRAM_TYPE     PROGRAM_ACTION       NUMBER_OF_ARGUMENTS ENABL

-------------------- ---------------- -------------------- ------------------- -----

  • MY_PROGRAM1          EXECUTABLE       /bin/ls                                1 FALSE

  由于前面创建program時並未指定NUMBER_OF_ARGUMENTS的值,因此我们这里需要首先修改该值为一个非0值,操作如下:

SQL> exec dbms_scheduler.set_attribute('my_program1','NUMBER_OF_ARGUMENTS',1);

  • PL/SQL procedure successfully completed.

  没错,操作还是使用DBMS_SCHEDULER.SET_ATTRIBUTE过程。另外需要注意,program的NUMBER_OF_ARGUMENTS参数可是说想改就能改的,正常情况下该处理必须是在program处于enabled之前确认完毕,否则会触发ORA-27465错误,因此要修改program的参数之前,必须首先确保要修改program的enabled状态为false。

  那么对于已经处于enabled状态的program,如何修改其状态属性呢?其实很简单,前面操作jobs时使用的DBMS_SCHEDULER.DISABLE过程还记的吗?没错,该过程对于program同样好使,并且调用方式也完全一样,例如:

SQL> exec dbms_scheduler.disable('my_program1');

  • PL/SQL procedure successfully completed.

  另外,如果希望将program置为enabled状态,执行DBMS_SCHEDULER.ENABLE过程即可,这里不再例举。

  接下来,就可以为刚刚创建的my_program1添加路径参数,操作如下:

SQL> BEGIN

  2  DBMS_SCHEDULER.DEFINE_PROGRAM_ARGUMENT (

  3     program_name            => 'my_program1',

  4     argument_position       => 1,

  5     argument_name           => 'dirpath',

  6     argument_type           => 'VARCHAR2',

  7     default_value           => '/home/oracle');

  8  END;

  9  /

  • PL/SQL procedure successfully completed.

  查询为program定义的参数,可以通过USER_SCHEDULER_PROGRAM_ARGS视图,例如:

SQL> select program_name,argument_name,argument_position,argument_type

  2  default_value from user_scheduler_program_args;

PROGRAM_NAME         ARGUMENT_NAME        ARGUMENT_POSITION DEFAULT_VALUE

-------------------- -------------------- ----------------- --------------------

  • MY_PROGRAM1          DIRPATH                              1 VARCHAR2

  删除program的argument操作也很简单,使用DROP_PROGRAM_ARGUMENT过程即可,例如:

SQL> exec dbms_scheduler.drop_program_argument('my_program1','dirpath');

  • PL/SQL procedure successfully completed.

  该过程第一个参数指定program名称,第二个参数指定定义的argument名称,当然此处也可以指定argument的位置,即前例视图返回结果中的 ARGUMENT_POSITION 列值。

  要删除program的话就更简单了,使用DROP_PROGRAM过程即可,例如:

SQL> exec dbms_scheduler.drop_program('my_program1');

  • PL/SQL procedure successfully completed.

  当然啦,删除program的同时,也会删除该program对应的所有arguments。

  实际上SCHEDULER中创建job时,也可以指定执行外部的程序。SCHEDULER中的Job更像是之前版本继承过来的JOBS,只不过10g中SCHEDULER管理的JOBS功能更加强大。Programs与Jobs不同的是,Jobs是定义好的,定时执行的任务,而Programs则是定义好的,等待被执行的对象。那么Programs是由谁来执行呢,不要走开,广告之后即将全面揭晓。

三、使用Schedules

  10g 中新推出的SCHEDULER可能确实会让很多初接触的朋友感觉晕头晕脑,相比之前的jobs,SCHEDULER中新增的概念太多。比如说jobs,仍然可以理解成之前版本中的jobs,不过功能更加强大(注意10g中也仍然可以使用普通jobs,这是废话,相信看本篇文章的朋友目前应该还是这样在用),比如说program,指的是运行的程序(把要做什么单提出来了),比如说schedule,我将其翻译为调度(job我翻译为任务),定义执行的频率或者说周期。

3.1  创建和管理Schedule s

  Schedule ,中文直译的话应该理解成调度,从名字来看,它是一个逻辑实体(逻辑,还实体,好矛盾),就是说当创建了schedule之后,数据库中就肯定存在这一对象,只不过这一对象是用来描述job的执行周期。

  创建schedule可以通过DBMS_SCHEDULER.CREATE_SCHEDULE过程,该过程支持的参数如下:

SQL> desc dbms_scheduler.create_schedule;

Parameter       Type                     Mode Default? 

--------------- ------------------------ ---- -------- 

SCHEDULE_NAME   VARCHAR2                 IN            

START_DATE      TIMESTAMP WITH TIME ZONE IN   Y        

REPEAT_INTERVAL VARCHAR2                 IN            

END_DATE        TIMESTAMP WITH TIME ZONE IN   Y        

  • COMMENTS        VARCHAR2                 IN   Y        

  各参数分别代表含意如下:

  • SCHEDULE_NAME :指定schedule名称,注意名称不能重复。
  • START_DATE :指定该调度的开始时间,可为空,当为空时表示该调度暂不起用。
  • REPEAT_INTERVAL :指定调度的执行频率或周期。
  • END_DATE :指定调度的结束时间,可为空,为空时就表示该调度将一直进行。
  • COMMENTS :注释信息。

  这其中,比较有技术含量的是REPEAT_INTERVAL参数,对于这个参数大家应该不会太陌生,因为前面介绍Jobs,也曾经提到过同名的参数,Schedules中的REPEAT_INTERVAL参数和Jobs中的REPEAT_INTERVAL参数功能完全相同,甚至参数格式也一模一样。

  REPEAT_INTERVAL 参数的语法结构要复杂的多。其中最重要的是FREQ和INTERVAL两个关键字。

  • FREQ 关键字用来指定间隔的时间周期,可选参数有:YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, and SECONDLY,分别表示年、月、周、日、时、分、秒等单位。
  • INTERVAL 关键字用来指定间隔的频繁,可指定的值的范围从1-99。

  比如说,当指定REPEAT_INTERVAL=>'FREQ=DAILY;INTERVAL=1';就表示每天执行一次,如果将INTERVAL改为7就表示每7天执行一次,效果等同于FREQ=WEEKLY;INTERVAL=1。

  下面,创建一个schedule,指定调度为每周一次的频率,执行脚本如下:

SQL> begin

  2  DBMS_SCHEDULER.CREATE_SCHEDULE (

  3    schedule_name     => 'my_first_schedule',

  4    start_date        => SYSDATE,

  5    repeat_interval   => 'FREQ=WEEKLY; INTERVAL=1',

  6    comments          => 'Every 1 weeks');

  7  END;

  8  /

  • PL/SQL procedure successfully completed.

  查询当前已经创建的schedules,可以通过*_SCHEDULER_SCHEDULES视图(含DBA_,ALL_,USER_),例如,查看当前用户拥有的schedules,执行语句如下:

SQL> select schedule_name,repeat_interval from user_scheduler_schedules;

SCHEDULE_NAME                  REPEAT_INTERVAL

------------------------------ ------------------------------

  • MY_FIRST_SCHEDULE              FREQ=WEEKLY; INTERVAL=1

  如果要修改schedule属性的话,也是使用DBMS_SCHEDULER.SET_ATTRIBUTE过程,该过程的调用方式前面已经多次演示过,这里就不再重复举例了,仅说明一点,对于schedule来说,能够修改的属性包括:REPEAT_INTERVAL、COMMENTS、END_DATE、START_DATE以及EVENT_SPEC。

  至于删除schedule,再简单不过,执行DBMS_SCHEDULER.DROP_SCHEDULE过程即可,例如:

SQL> EXEC DBMS_SCHEDULER.DROP_SCHEDULE('MY_FIRST_SCHEDULE');

  • PL/SQL procedure successfully completed.

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.

  创建job时,start_date,repeat_interval,job_action等均无须指定,因为这些参数将由program和schedule来控制。

  这样,操作完成后,ORACLE就会自动定时(当前设置为每周执行一次)program中定义的操作。

  要查看当前的执行情况,通过*_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特性的功能还多着哪,接着往下看吧。

3.3 设置Repeat Interval

  Job 和Schedule中REPEAT_INTERVAL参数都是用来控制执行的频率或周期,虽然说周期是一个时间性概念,不过REPEAT_INTERVAL指定的时候并不是一个时间值,而是由一组关键字描述的时间。

  除了前面介绍Job和Schedule的REPEAT_INTERVAL参数时,提到该参数拥有FREQ以及INTERVAL两个关键字,其实除此之外,还有如BYMONTH、BYWEEKNO、BYYEARDAY、BYDATE等等参数,可以用来进行更精确的定义,比如通过BYMONTH关键字指定调度运行的月份,BYDAY指定调度在哪天运行等等。

  REPEAT_INTERVAL 参数的详细语法如下:

repeat_interval = regular_schedule | combined_schedule

==============================

regular_schedule = frequency_clause

[";" interval_clause] [";" bymonth_clause] [";" byweekno_clause]

[";" byyearday_clause] [";" bydate_clause] [";" bymonthday_clause]

[";" byday_clause] [";" byhour_clause] [";" byminute_clause]

[";" bysecond_clause] [";" bysetpos_clause] [";" include_clause]

[";" exclude_clause] [";" intersect_clause][";" periods_clause]

[";" byperiod_clause]

==============================  

combined_schedule = schedule_list [";" include_clause]

[";" exclude_clause] [";" intersect_clause]

frequency_clause = "FREQ" "=" ( predefined_frequency | user_defined_frequency )

predefined_frequency = "YEARLY" | "MONTHLY" | "WEEKLY" | "DAILY" | 

   "HOURLY" | "MINUTELY" | "SECONDLY"

user_defined_frequency = named_schedule

==============================

interval_clause = "INTERVAL" "=" intervalnum

   intervalnum = 1 through 99

bymonth_clause = "BYMONTH" "=" monthlist

   monthlist = monthday ( "," monthday)*

   month = numeric_month | char_month

   numeric_month = 1 | 2 | 3 ...  12

   char_month = "JAN" | "FEB" | "MAR" | "APR" | "MAY" | "JUN" |

   "JUL" | "AUG" | "SEP" | "OCT" | "NOV" | "DEC"

byweekno_clause = "BYWEEKNO" "=" weeknumber_list

   weeknumber_list = weeknumber ( "," weeknumber)*

   weeknumber = [minus] weekno

   weekno = 1 through 53

byyearday_clause = "BYYEARDAY" "=" yearday_list

   yearday_list = yearday ( "," yearday)*

   yearday = [minus] yeardaynum

   yeardaynum = 1 through 366

bydate_clause = "BYDATE" "=" date_list

   date_list = date ( "," date)*

   date = [YYYY]MMDD [ offset | span ]

bymonthday_clause = "BYMONTHDAY" "=" monthday_list

   monthday_list = monthday ( "," monthday)*

   monthday = [minus] monthdaynum

   monthdaynum = 1 through 31

byday_clause = "BYDAY" "=" byday_list

   byday_list = byday ( "," byday)*

   byday = [weekdaynum] day

   weekdaynum = [minus] daynum

   daynum = 1 through 53 /* if frequency is yearly */

   daynum = 1 through 5  /* if frequency is monthly */

   day = "MON" | "TUE" | "WED" | "THU" | "FRI" | "SAT" | "SUN"

byhour_clause = "BYHOUR" "=" hour_list

   hour_list = hour ( "," hour)*

   hour = 0 through 23

byminute_clause = "BYMINUTE" "=" minute_list

   minute_list = minute ( "," minute)*

   minute = 0 through 59

bysecond_clause = "BYSECOND" "=" second_list

   second_list = second ( "," second)*

   second = 0 through 59

bysetpos_clause = "BYSETPOS" "=" setpos_list

   setpos_list = setpos ("," setpos)*

   setpos = [minus] setpos_num

   setpos_num = 1 through 9999

==============================

include_clause = "INCLUDE" "=" schedule_list

exclude_clause = "EXCLUDE" "=" schedule_list

intersect_clause = "INTERSECT" "=" schedule_list

schedule_list = schedule_clause ("," schedule_clause)*

schedule_clause = named_schedule [ offset ]

named_schedule = [schema "."] schedule

periods_clause = "PERIODS" "=" periodnum

byperiod_clause = "BYPERIOD" "=" period_list

period_list = periodnum ("," periodnum)*

periodnum = 1 through 100

==============================

offset = ("+" | "-") ["OFFSET:"] duration_val

span = ("+" | "-" | "^") "SPAN:" duration_val

duration_val = dur-weeks | dur_days

dur_weeks = numofweeks "W"

dur_days = numofdays "D"

numofweeks = 1 through 53

numofdays = 1 through 376

  • minus = "-"

  这个语法形式看起来复杂无比,其实实用起来很简单,之所以看起来复杂,是因为其功能太过灵活(之前的三思系列笔记中,已经阐述过灵活与复杂的关系),这里不准备逐条解释每一个语法细节,下面将着重通过一些常用设置,希望能够更有助于广大同仁的理解。

  例如:设置任务仅在周5的时候运行:

REPEAT_INTERVAL => 'FREQ=DAILY; BYDAY=FRI';

REPEAT_INTERVAL => 'FREQ=WEEKLY; BYDAY=FRI';

  • REPEAT_INTERVAL => 'FREQ=YEARLY; BYDAY=FRI';

  上述三条语句虽然指定的关键字小有差异,不过功能相同。

  设置任务隔一周运行一次,并且仅在周5运行:

  • REPEAT_INTERVAL => 'FREQ=WEEKLY; INTERVAL=2; BYDAY=FRI';

  设置任务在当月最后一天运行:

  • REPEAT_INTERVAL => 'FREQ=MONTHLY; BYMONTHDAY=-1';

  设置任务在3月10日运行:

  • REPEAT_INTERVAL => 'FREQ=YEARLY; BYMONTH=MAR; BYMONTHDAY=10';
  • REPEAT_INTERVAL => 'FREQ=YEARLY; BYDATE=0310';

  上述两条语句功能相同。

  设置任务每10隔天运行:

  • REPEAT_INTERVAL => 'FREQ=DAILY; INTERVAL=10';

  设置任务在每天的下午4、5、6点时运行:

  • REPEAT_INTERVAL => 'FREQ=DAILY; BYHOUR=16,17,18';

  设置任务在每月29日运行:

  • REPEAT_INTERVAL => 'FREQ=MONTHLY; BYMONTHDAY=29';

  设置任务在每年的最后一个周5运行:

  • REPEAT_INTERVAL => 'FREQ=YEARLY; BYDAY=-1FRI';

  设置任务每隔50个小时运行:

  • REPEAT_INTERVAL => 'FREQ=HOURLY; INTERVAL=50';

  另外,你是否在怀念常规job中设置interval的简便,虽然功能较弱,但是设置操作非常简单,无须懊恼,其实SCHEDULER中的REPEAT_INTERVAL也完全可以按照那种方式设置,前面都说了,REPEAT_INTERVAL实际上是指定周期,直接指定一个时间值,当然也是周期喽。

  比如说,设置任务每天执行一次,也可以设置REPEAT_INTERVAL参数值如下:

  • REPEAT_INTERVAL => 'trunc(sysdate)+1'

  又比如设置任务每周执行一次:

  • REPEAT_INTERVAL => 'trunc(sysdate)+7'

  不过需要注意,这种方式仅用于创建SCHEDULER中jobs时使用,不能用于schedule。

四、使用Events

  Event直译对应的中文解释是指事件,不过单纯讲事件毕竟太抽象了,举个示例来形容吧。A(对应某个应用程序,或者是ORACLE中的进程)在干活时突然眉头一皱说道,不好,前方有情况,这可怎么办!这时,只见它认真想了想,过了一会儿脸上一喜说道:有了,俗话说早请示啊晚汇报,出现情况要找领导,赶紧给领导发消息呗!于是B(也是对应某个应用或ORACLE进程)就收到了一条A发过来的"前方有XX情况"的消息,这个过程就叫EVENT(含A发消息以及B接收消息)。

  SCHEDULER 中有两种触发EVENT的情况:

  • Scheduler 触发的Events

    Scheduler 中触发的Events,一般是说当前schduler中job的状态发生修改,类似job启动,或者运行结束,或者达到运行时间等诸如此类的动作,都能够抛出一个EVENT,接收到EVENT的applicate就可以根据这些信息进行适当的处理。

    比如说,由于系统太过于繁忙,超出job启动时间后30分钟,job仍然没能顺利启动,那么这个时候,Scheduler就可以抛出一条EVENT给外部的应用,以便外部应用能够及时通知DBA,进行处理。

  • application 触发的Events

    外部的应用也可以触发Events,并且由Scheduler来接收并处理这一类型的Events。所谓Scheduler处理EVENT就是指Scheduler启动相应的job来执行相关操作,这类job在创建时专门声明了event的处理,这样当接收到EVENT时,这类job就会启动。

  Scheduler 使用Oracle高级队列来抛出以及销毁Events。当抛出Schduler触发的Events时,Scheduler将消息入队到默认的event队列,application则通过检查该队列来处理Events。当抛出application触发的Events时,application将消息入队到处理job对应的队列中。

  下面我们也按照这两个类型来介绍Scheduler中的Events。

4.1 Scheduler抛出的Events

  前面说了,Scheduler抛出的Events一般是指job状态改变时触发的,那么是不是说只要job状态发生了改变,就会触发Events,其实并非如此,因为默认情况下,job是不触发Events的。

  Scheduler 中的job有一个属性叫raise_events,专门用来设置job触发Events的条件,该属性在CREATE_JOB时不能执行,因此默认情况下该属性不会赋值,自然也就不会触发EVENT。要设置raise_events属性,只能是在job创建完成后,通过SET_ATTRIBUTE过程修改job的raise_events属性。

  例如,修改前面创建的job-,启用raise_events属性,执行语句如下:

SQL> BEGIN

  2  DBMS_SCHEDULER.SET_ATTRIBUTE('INSERT_TEST_TBL', 'raise_events',  DBMS_SCHEDULER.JOB_ALL_EVENTS)

  3  END;

  4  /

  • PL/SQL procedure successfully completed.

  上述示例中指定的raise_events属性的属性值DBMS_SCHEDULER.JOB_ALL_EVENTS,就是抛出Events的触发条件。

  触发Events的有下列的类型,分别代表不同的操作:

  • job_started :JOB启动;
  • job_succeeded :JOB成功结束;
  • job_failed :JOB执行失败;
  • job_broken :JOB被置为BROKEN状态;
  • job_completed :JOB达到最大运行次数,或者运行的结束日期;
  • job_stopped :JOB被STOP_JOB过程置为停止执行的状态;
  • job_sch_lim_reached :Job的schedule达到限定值;
  • job_disabled :JOB被置于DISABLE状态;
  • job_chain_stalled :运行于chain的JOB被置于CHAIN_STALLED状态;
  • job_all_events :含上述提到的所有类型;
  • job_run_completed :由于Job运行出错、成功结束或被手动停止。

  起用raise_events后,Scheduler就会按照设定的触发条件,当达到触发条件时,即会抛出事件信息到SYS.SCHEDULER$_EVENT_QUEUE队列。

  例如,手动执行一次INSERT_TEST_TBL,看看是否向队列中记录信息,操作如下:

SQL> exec dbms_scheduler.run_job('INSERT_TEST_TBL');

  • PL/SQL procedure successfully completed.

  执行下列脚本,出队数据:

SQL> set serveroutput on

SQL> DECLARE

  2    l_dequeue_options    DBMS_AQ.dequeue_options_t;

  3    l_message_properties DBMS_AQ.message_properties_t;

  4    l_message_handle     RAW(16);

  5    l_queue_msg          sys.scheduler$_event_info;

  6  BEGIN

  7    l_dequeue_options.consumer_name := 'TEST';

  8

  9    DBMS_AQ.dequeue(queue_name         => 'SYS.SCHEDULER$_EVENT_QUEUE',

 10                    dequeue_options    => l_dequeue_options,

 11                    message_properties => l_message_properties,

 12                    payload            => l_queue_msg,

 13                    msgid              => l_message_handle);

 14    COMMIT;

 15

 16    DBMS_OUTPUT.put_line('event_type : ' || l_queue_msg.event_type);

 17    DBMS_OUTPUT.put_line('object_owner : ' || l_queue_msg.object_owner);

 18    DBMS_OUTPUT.put_line('object_name : ' || l_queue_msg.object_name);

 19    DBMS_OUTPUT.put_line('event_timestamp: ' || l_queue_msg.event_timestamp);

 20    DBMS_OUTPUT.put_line('error_code : ' || l_queue_msg.error_code);

 21    DBMS_OUTPUT.put_line('event_status : ' || l_queue_msg.event_status);

 22    DBMS_OUTPUT.put_line('log_id : ' || l_queue_msg.log_id);

 23    DBMS_OUTPUT.put_line('run_count : ' || l_queue_msg.run_count);

 24    DBMS_OUTPUT.put_line('failure_count : ' || l_queue_msg.failure_count);

 25    DBMS_OUTPUT.put_line('retry_count : ' || l_queue_msg.retry_count);

 26  END;

 27  /

event_type : JOB_STARTED

object_owner : TEST

object_name : INSERT_TEST_TBL

event_timestamp: 25-AUG-09 12.49.29.558758 PM +08:00

error_code : 0

event_status : 1

log_id :

run_count : 1

failure_count : 0

retry_count : 0

  • PL/SQL procedure successfully completed.

  从返回的信息可以看到,event的类型为JOB_STARTED,表示JOB启动。实际上job:INSERT_TEST_TBL执行一次至少会向队列中插入两条event信息,一条为JOB_STARTED,一条则为JOB_SUCCEEDED(也可能是JOB_FAILED),这里不详细演示,感兴趣的朋友不妨自行测试。

  • 提示:SYS.SCHEDULER$_EVENT_QUEUE队列基于SYS.SCHEDULER$_EVENT_QTAB队列表,因此查询SYS.SCHEDULER$_EVENT_QTAB也可以获取上述的信息。

  SYS.SCHEDULER$_EVENT_QUEUE 是一个固定队列,实际应用的过程中,DBA应该根据实际情况,将该表访问权限授予相关用户,以便顺利出队该队列中的events信息。

  另外,友情提醒,默认情况下Scheduler仅保留最近24小时的Events信息,如果希望修改该设置的话,可以通过SET_SCHEDULER_ATTRIBUTE过程,修改scheduler的event_expiry_time属性,该项属性的属性值以秒为单位。

4.2 Application抛出的Events

  首先要说明,这里所说的Application是个代词,即可以表示ORACLE数据库之外的应用程序,也可以是ORACLE数据库中的PROCEDURE等对象,总之你就将其理解成用户自己创建的对象就好了。

  Scheduler 能够抛出Events让外部应用处理,外部的应用也可以抛出Events让Scheduler启动job处理,不过并不是任何job都能够对外部应用抛出的Events做出响应,必须在创建jobs时明确指定响应的事件。那么如何指定呢?依靠下列两个附加的参数:

  • queue_spec :指定外部应用抛出的events消息入队的队列名;
  • event_condition :指定触发job启动的条件,这一参数的参数值在设置时应当基于事件消息的自身属性,因为事件消息在入队时,消息的属性都是由application定义的,因此在设置触发条件时,也应该根据这些属性值就行设置。

  下面,我们就演示创建一个由event触发启动的job,在此之前,首先需要进行一些准备工具,比如创建队列,由于队列需要基于一个队列表,因此在创建队列之前,首先要创建一个队列表,考虑到队列表需要依赖一个对象类型,因此在创建队列表之前,先得创建一个type.......复杂,具体的操作步骤如下,客官可要看仔细了:

SQL> create or replace type jss_type 1  as object

  2  (

  3    event_type         VARCHAR2( 1 0),

  4    object_owner       VARCHAR2( 30 ),

  5    object_name        VARCHAR2( 3 0)

  6  );

  7  /

Type created.

SQL> begin

  2    dbms_aqadm.create_queue_table(

  3      queue_table        => 'my_queue_tbl1',

  4      queue_payload_type => 'JSS_TYPE1',

  5      multiple_consumers => true);

  6  end;

  7  /

PL/SQL procedure successfully completed.

SQL> begin

  2    dbms_aqadm.create_queue(

  3      queue_name  => 'event_t1',

  4      queue_table => 'my_queue_tbl1');

  5  end;

  6  /

  • PL/SQL procedure successfully completed.

  OK, 准备工作完成,下面就来创建一个event触发启动的job,创建脚本如下:

SQL> BEGIN

  2  DBMS_SCHEDULER.CREATE_JOB (

  3     job_name            =>  'EVENT_JOB_T1',

  4     job_type            =>  'STORED_PROCEDURE',

  5     job_action          =>  'P_INSERTINTOTEST',

  6     event_condition     =>  'tab.user_data.event_type = ''OP_INSERT''',

  7     queue_spec          =>  'EVENT_T1',

  8     enabled             =>  TRUE);

  9  END;

 10  /

  • PL/SQL procedure successfully completed.

  上述脚本仅做演示,因此创建的job仍然执行P_INSERTINTOTEST过程。

  三思并不准备再编写一套外部的应用来触发,这里仅为了演示application触发job启动的示例,因此三思决定通过pl/sql直接向event_t1队列中添加消息的方式,触发job的启动,具体操作如下。

  首先要执行DBMS_AQADM.START_QUEUE过程,将event_t1置于允许入队和出队状态(默认情况下创建的队列是不允许出队和入队操作的),脚本如下:

SQL> exec dbms_aqadm.start_queue(queue_name => 'event_t1',enqueue => true,dequeue => true);

  • PL/SQL procedure successfully completed.

  执行入队操作:

SQL> declare

  2    v_Message           jss_type1;

  3    v_EnqueueOptions    dbms_aq.enqueue_options_t;

  4    v_MessageProperties dbms_aq.message_properties_t;

  5    v_msg_handle        raw(16);

  6  begin

  7    v_message := jss_type1('OP_ SELECT ', user, 'tmpObj');

  8

  9    dbms_aq.enqueue(queue_name         => 'event_t1',

 10                    enqueue_options    => v_enqueueOptions,

 11                    message_properties => v_messageproperties,

 12                    payload            => v_message,

 13                    msgid              => v_msg_handle);

 14    commit;

 15

 16  end;

 17  /

  • PL/SQL procedure successfully completed.

  查询队列表中的数据:

SQL> select user_data from my_queue_tbl1;

USER_DATA(EVENT_TYPE, OBJECT_OWNER, OBJECT_NAME)

---------------------------------------------------------

  • JSS_TYPE1('OP_SELECT', 'TEST', 'tmpObj')

  然后查询job

SQL> select to_char(created,'yyyy-mm-dd hh24:mi:ss') from jss_1;

TO_CHAR(CREATED,'YY

-------------------

  • 2009-08-25 12:49:29

  看起来jss_1表中并未有新增加记录,似乎job没有执行啊。这很正常,还记得咱们创建job时指定的 event_condition 条件吗:

  •   6     event_condition     =>  'tab.user_data.event_type = ''OP_INSERT''',

  没错,只有当event_type为'OP_INSERT'时才会触发job的执行,前面入队时指定的是 OP_ SELECT ,当然没有触发job中指定的procedure啦,下面再次执行入队操作:

SQL> declare

  2    v_Message           jss_type1;

  3    v_EnqueueOptions    dbms_aq.enqueue_options_t;

  4    v_MessageProperties dbms_aq.message_properties_t;

  5    v_msg_handle        raw(16);

  6  begin

  7    v_message := jss_type1('OP_INSERT', user, 'tmpObj');

  8

  9    dbms_aq.enqueue(queue_name         => 'event_t1',

 10                    enqueue_options    => v_enqueueOptions,

 11                    message_properties => v_messageproperties,

 12                    payload            => v_message,

 13                    msgid              => v_msg_handle);

 14    commit;

 15

 16  end;

  •  17  /

  再次查看jss_1表看看:

SQL> select to_char(created,'yyyy-mm-dd hh24:mi:ss') from jss_1;

TO_CHAR(CREATED,'YY

-------------------

2009-08-25 12:49:29

  • 2009-08-25 13:21:21

  多了一条记录,说明job已经被自动触发。

  最后再补充一句,基于event的job不能通过DBMS_SCHEDULER.RUN_JOB过程执行,否则会触发ORA-00942: table or view does not exist错误。

五、使用Chains

  今天要来认识一位新同学:CHAIN(注意不要敲成CHINA)。CHAIN可以被视做一组Programs的复合,举个简单的例子:运行PROGRAM:A以及PROGRAM:B,如果成功的话继续运行PROGRAM:C,否则的话运行PROGRAM:D。Programs:A、B、C、D以及执行的逻辑关系就构成了一个最简单的CHAIN。

  关于CHAIN的管理操作比较多,比如创建/删除/修改Chains,添加/修改/删除Chain Steps等等。

5.1  创建Chains

5.1.1  创建CHAIN对象

  创建CHAIN使用DBMS_SCHEDULER.CREATE_CHAIN过程,这个过程调用非常简单,因为需要指定的参数极少,该过程的定义如下:

SQL> desc dbms_scheduler.create_chain;

Parameter           Type                   Mode Default? 

------------------- ---------------------- ---- -------- 

CHAIN_NAME          VARCHAR2               IN            

RULE_SET_NAME       VARCHAR2               IN   Y        

EVALUATION_INTERVAL INTERVAL DAY TO SECOND IN   Y        

  • COMMENTS            VARCHAR2               IN   Y        

  在创建时,甚至可以简单到只指定一个CHAIN的名称,其它均为空即可,例如:

SQL> exec dbms_scheduler.create_chain('my_chain1');

  • PL/SQL procedure successfully completed.

  定义好的Chains,可以通过*_SCHEDULER_CHAINS视图查看,例如:

SQL> select chain_name from user_scheduler_chains;

CHAIN_NAME

------------------------------

  • MY_CHAIN1

  注意,不是说创建了CHAIN就齐活,只有一个CHAIN对象ORACLE还是啥也干不了(当然啦,相信从上面执行的创建语句大家也看出来了),CHAIN对象创建之后,要做的工作其实才刚刚开始。其后,还需要定义Chain Steps以及Chain rules。

5.1.2  创建Chain Step

  Chain Steps 就是用来指定CHAIN执行的操作及执行步骤,创建CHAIN STEP是通过DBMS_SCHEDULER.DEFINE_CHAIN_STEP过程进行,例如,为刚刚创建的my_chain1添加一个step,执行操作如下:

SQL> begin

  2  DBMS_SCHEDULER.DEFINE_CHAIN_STEP (

  3     chain_name      =>  'my_chain1',

  4     step_name       =>  'my_step1',

  5     program_name    =>  'p_p1');

  6  end;

  7  /

  • PL/SQL procedure successfully completed.

  Chain Steps 即可以调用PROGRAM(注意是program,不是procedure,当然program中可以定义执行procedure),也可以调用EVENT,甚至调用其它CHAIN(这就叫嵌套CHAIN)。

  下面接着为my_chain1添加两个step,操作如下:

SQL> begin

  2  DBMS_SCHEDULER.DEFINE_CHAIN_STEP (

  3     chain_name      =>  'my_chain1',

  4     step_name       =>  'my_step2',

  5     program_name    =>  'p_p2');

  6  DBMS_SCHEDULER.DEFINE_CHAIN_STEP (

  7     chain_name      =>  'my_chain1',

  8     step_name       =>  'my_step3',

  9     program_name    =>  'p_p3');

 10  end;

 11  /

  • PL/SQL procedure successfully completed.

  要查询定义的Chain Steps,则是通过*_SCHEDULER_CHAIN_STEPS视图,例如:

SQL> select chain_name,step_name,program_name from user_scheduler_chain_steps;

CHAIN_NAME           STEP_NAME            PROGRAM_NAME

-------------------- -------------------- --------------------

MY_CHAIN1            MY_STEP1             P_P1

MY_CHAIN1            MY_STEP2             P_P2

  • MY_CHAIN1            MY_STEP3             P_P3

5.1.3  创建Chain Rule

  接下来,要为CHAIN的运行定义规则。定义规则是使用DBMS_SCHEDULER.DEFINE_CHAIN_RULE过程,Chain Rules依赖于Chain Steps,每个CHAIN RULE都拥有condition和action属性,当满足condition时则执行action中指定的step。

  DBMS_SCHEDULER.DEFINE_CHAIN_RULE 过程的语法如下:

SQL> desc dbms_scheduler.define_chain_rule;

Parameter  Type     Mode Default? 

---------- -------- ---- -------- 

CHAIN_NAME VARCHAR2 IN            

CONDITION  VARCHAR2 IN            

ACTION     VARCHAR2 IN            

RULE_NAME  VARCHAR2 IN   Y        

  • COMMENTS   VARCHAR2 IN   Y        

  CHAIN_NAME 就不说了,需要注意的是CONDITION和ACTION两个参数。在为condition参数指定值时,其语法看起来稍稍复杂一些,或者说是灵活,condition参数值支持下列的语法形式:

  • TRUE
  • FALSE
  • stepname [NOT] SUCCEEDED 
  • stepname [NOT] FAILED 
  • stepname [NOT] STOPPED 
  • stepname [NOT] COMPLETED 
  • stepname ERROR_CODE IN (integer, integer, integer ...)
  • stepname ERROR_CODE NOT IN (integer, integer, integer ...)
  • stepname ERROR_CODE = integer
  • stepname ERROR_CODE != integer
  • stepname ERROR_CODE <> integer
  • stepname ERROR_CODE > integer
  • stepname ERROR_CODE >= integer
  • stepname ERROR_CODE < integer
  • stepname ERROR_CODE <= integer

  甚至于,还可以制定成下列逻辑语法:

  • expression AND expression
  • expression OR expression
  • NOT (expression)

  比如说,我们希望条件为step1成功运行,那么可以指定condition参数值如下:

  • 'step1 completed'

  Action 参数相对简单一些,这个参数用来指定当满足condition参数时,CHAIN执行的操作。

  例如,创建CHAIN RULE,首先执行my_step1,如果my_step1成功执行的话,就继续执行my_step2,如果my_step2也成功执行的话,则结束该CHAIN,创建脚本如下:

SQL> BEGIN

  2  DBMS_SCHEDULER.DEFINE_CHAIN_RULE (

  3     chain_name   =>   'my_chain1',

  4     condition    =>   'TRUE',

  5     action       =>   'START my_step1',

  6     rule_name    =>   'my_rule1');

  7  DBMS_SCHEDULER.DEFINE_CHAIN_RULE (

  8     chain_name   =>   'my_chain1',

  9     condition    =>   'my_step1 completed',

 10     action       =>   'START my_step2',

 11     rule_name    =>   'my_rule2');

 12  DBMS_SCHEDULER.DEFINE_CHAIN_RULE (

 13     chain_name   =>   'my_chain1',

 14     condition    =>   'my_step2 completed',

 15     action       =>   'end 0',

 16     rule_name    =>   'my_rule3');

 17  END;

 18  /

  • PL/SQL procedure successfully completed.

5.1.4  运行Chains

  最后,来运行一下创建的my_chain1吧,手动运行CHAIN是通过DBMS_SCHEDULER.RUN_CHAIN过程,例如:

SQL> BEGIN

  2  DBMS_SCHEDULER.RUN_CHAIN (

  3     chain_name    =>  'my_chain1',

  4     start_steps   =>  'my_step1');

  5  END;

  6  /

  • PL/SQL procedure successfully completed.

  语句执行成功,下面需要查看一下执行的结果。我们之前定义的p_p1等program对象,实际上是调用procedure,向一个指定表jss_t2中插入记录,这里直接查询一下该表,就知道执行情况了(在此之前,jss_t2表为空):

SQL> select * from jss_t2;

TP                             DT

------------------------------ ------------

p_p1 inserted                  03-SEP-09

  • p_p2 inserted                  03-SEP-09

  你看,jss_t2表中有了两条记录,对应前面设置的CHAIN RULE,说明my_step1和my_step2均已正确执行。

  • 提示:Chains在执行前,必须被置于enabled状态,默认情况下刚刚创建的CHAIN都是disabled状态,要修改Chains的状态,还是通过DBMS_SCHEDULER.ENABLE和DBMS_SCHEDULER.DISABLE两过程,这里就不演示了。

  手动执行的CHAIN的话没有系统级的日志记录,因此如果希望看到详细执行情况的话,建议创建job来执行CHAIN,例如:

SQL> BEGIN

  2  DBMS_SCHEDULER.CREATE_JOB (

  3     job_name        => 'chain_job_1',

  4     job_type        => 'CHAIN',

  5     job_action      => 'my_chain1',

  6     repeat_interval => 'freq=daily;interval=1',

  7     enabled         => TRUE);

  8  END;

  9  /

  • PL/SQL procedure successfully completed.

  然后,dba就可以通过定期观察*_scheduler_job_run_details视图来确认chain的执行情况了。

5.2  管理Chains

5.2.1  修改Chains属性

  基本上碰到修改CHAIN属性的机率不会太大,因此确实没啥可修改的,对于CHAIN对象来说,能够修改的属性只有两个:evaluation_interval和comments,这两个参数一般情况下甚至都不会进行设置。如果你碰到了确实需要修改的情况,没问题,DBMS_SCHEDULER.SET_ATTRIBUTE过程还记的吧,没错,修改CHAIN也是用它。例如:

SQL> select chain_name,comments from user_scheduler_chains;

CHAIN_NAME           COMMENTS

-------------------- --------------------------

MY_CHAIN1

SQL>  exec dbms_scheduler.set_attribute('my_chain1','comments','change it for a test!');

PL/SQL procedure successfully completed.

SQL> select chain_name,comments from user_scheduler_chains;

CHAIN_NAME           COMMENTS

-------------------- --------------------------

  • MY_CHAIN1            change it for a test !

5.2.2  设置Chain Step运行属性

  修改Chain Step的运行属性就不能使用DBMS_SCHEDULER.SET_ATTRIBUTE了,而是有专门的过程DBMS_SCHEDULER.ALTER_CHAIN处理,该过程的定义如下:

SQL> desc dbms_scheduler.alter_chain;

Parameter  Type     Mode Default? 

---------- -------- ---- -------- 

CHAIN_NAME VARCHAR2 IN            

STEP_NAME  VARCHAR2 IN            

ATTRIBUTE  VARCHAR2 IN            

  • VALUE      BOOLEAN  IN      

  前两个参数就不说了,ATTRIBUTE参数用来指定STEP的属性值,可设定的属性值有3个,每个属性值都有TRUE和FALSE两个选项,由VALUE参数指定:

  • PAUSE :设置该参数值为TRUE时,当step运行时,其运行状态就会变更为PAUSED;
  • SKIP :设置该参数值为TRUE时,当step满足运行条件时,并不是执行step中的program,而是直接跳过,注意当SKIP参数值设置为TRUE,并且PAUSE参数值也被设置为TRUE,那么将会以PAUSE的状态优先;
  • RESTART_ON_RECOVERY :设置该参数值为TRUE时,如果由于数据库shutdown导致step被停止,那么当下次数据库启动时,step会自动重新运行。

  DBMS_SCHEDULER.ALTER_CHAIN 过程修改Chain Step属性后,只有当下次运行时才会生效,如果要修改当前运行中Chain Step的属性,也有一个专门的过程DBMS_SCHEDULER.ALTER_RUNNING_CHAIN进行处理,该过程语法与DBMS_SCHEDULER.ALTER_CHAIN一模一样,这里就不详细介绍了。

5.2.3  删除Chain Rules

  Chain Rules 没有对应的修改方法,如果要修改某个Chain的rule,只能首先删除不适当的rule,然后重新添加新rule(所谓添加,其实就是再重新定义一个rule)。

  删除Chain Rule有专门的过程DBMS_SCHEDULER.DROP_CHAIN_RULE,该过程语法如下:

SQL> desc dbms_scheduler.drop_chain_rule;

Parameter  Type     Mode Default? 

---------- -------- ---- -------- 

CHAIN_NAME VARCHAR2 IN            

RULE_NAME  VARCHAR2 IN            

  • FORCE      BOOLEAN  IN   Y         

  三思一眼就能看出来,这个过程的调用方式那是相当简单,因此就不对各个参数详细介绍了,下面举个简单的示例,比如删除前面定义的my_rule3,执行过程如下:

SQL> exec dbms_scheduler.drop_chain_rule('my_chain1','my_rule3',true);

  • PL/SQL procedure successfully completed.

5.2.4  删除Chain Steps

  删除Chain Step也有专门的过程DBMS_SCHEDULER.DROP_CHAIN_STEP进行处理,该过程语法如下:

SQL> desc dbms_scheduler.drop_chain_step;

Parameter  Type     Mode Default? 

---------- -------- ---- -------- 

CHAIN_NAME VARCHAR2 IN            

STEP_NAME  VARCHAR2 IN            

  • FORCE      BOOLEAN  IN   Y   

  看着有点儿眼熟是吧,没错,与drop_chain_rule的相似度高达90%以上。例如,删除之前定义的my_step3,执行过程如下:

SQL> exec dbms_scheduler.drop_chain_step('my_chain1','my_step3',true);

  • PL/SQL procedure successfully completed.

5.2.5  删除Chains

  如果要删除Chain那就更简单了,执行dbms_scheduler.drop_chain过程即可,例如:

SQL> exec dbms_scheduler.drop_chain('my_chain1',true);

  • PL/SQL procedure successfully completed.

  注意,执行drop_chain时,如果不指定force参数为TRUE,那么默认情况下ORACLE会首先检查要删除的CHAIN是否还有被依赖的对象,如果存在的话,会报ORA-27479错误,提示仍然有依赖的对象(所谓依赖的对象就是指,该chain仍然存在chain_step或chain_rule之类),因此无法直接删除。这种情况下解决方案有两种:一是手动删除所有相关的chain_step和chain_rule,然后再执行chain的删除,再就是附加force参数并指定参数值为true,这样ORACLE就会自动替你清除所有依赖的对象了。

    

六、使用Job Classes

  Job Classes 相当于创建了一个job组,DBA可以将那些具有相同特性的job,统统放到相同的Job Classes中,然后通过对Job Class应用ORACLE中的"资源使用计划"特性,就可以对这些job执行过程中所需要的资源分配情况进行管理。

1、 创建Job Classes

  使用DBMS_SCHEDULER包的CREATE_JOB_CLASS过程创建Job Classes,该过程支持的参数如下:

JSSWEB>  desc dbms_scheduler.create_job_class;

Parameter               Type           Mode Default? 

----------------------- -------------- ---- -------- 

JOB_CLASS_NAME          VARCHAR2       IN            

RESOURCE_CONSUMER_GROUP VARCHAR2       IN   Y        

SERVICE                 VARCHAR2       IN   Y        

LOGGING_LEVEL           BINARY_INTEGER IN   Y        

LOG_HISTORY             BINARY_INTEGER IN   Y        

  • COMMENTS                VARCHAR2       IN   Y     

  其中:

  • JOB_CLASS_NAME :要创建的Job Class的名称,注意指定的长度不要超过30个字符,也不要与现有Job Class同名;
  • RESOURCE_CONSUMER_GROUP :指定创建的Job Class所在的RCG;

提示:啥是Resource Consumer Group

  • 你可以将其理解成一个资源分配的方式,处于相同RCG组中的用户、会话、或者对象共用一组资源,这组资源中可供分配的资源按照DBA指定的方式分配给RCG。如果设计合理,通过这种方式,可以更有效的利用服务器的资源。
  • SERVICE :指定创建的Job Class所在Service,本选项常见于RAC环境,我们都知道RAC环境由多实例+数据库组成,此处所指定的Service实际就是指Job Class会在哪个实例上运行。
  • 注意:本参数与RESOURCE_CONSUMER_GROUP参数相互冲突,同一个Job Class只同设置两个参数中的一个值。
  • LOGGING_LEVEL :指定日志记录的级别,有下列三种级别:
    • n  DBMS_SCHEDULER.LOGGING_OFF :关闭日志记录功能;
    • n  DBMS_SCHEDULER.LOGGING_RUNS :对该Job Class下所有任务的运行信息进行记录;
    • n  DBMS_SCHEDULER.LOGGING_FULL :记录该Job Class下任务的所有相关信息,不仅有任务的运行情况,甚至连任务的创建、修改等也均将记入日志。
  • LOG_HISTORY :指定日志记录的时间,以天为单位,比如指定LOG_HISTORY参数值为90,就表示日志信息保留最近90天的内容。
  • COMMENTS :指定注释信息。

  上述各个参数,除了LOG_CLASS_NAME参数为必选参外,其它均为可选参数,例如:

JSSWEB>  EXEC DBMS_SCHEDULER.CREATE_JOB_CLASS(¨my_first_jc¨);

  • PL/SQL procedure successfully completed

  查询系统中已经存在的Job Classes,可以通过DBA_SCHEDULER_JOB_CLASSES视图(或ALL_SCHEDULER_JOB_CLASS视图),例如:

JSSWEB> select job_class_name,resource_consumer_group,service from dba_scheduler_job_classes;

JOB_CLASS_NAME                 RESOURCE_CONSUMER_GROUP        SERVICE

------------------------------ ------------------------------ -----------------------------

DEFAULT_JOB_CLASS

AUTO_TASKS_JOB_CLASS           AUTO_TASK_CONSUMER_GROUP

  • MY_FIRST_JC

  当创建Jobs时,可以通过JOB_CLASS参数来指定job所在的Job Class,如果不指定的话,创建的job默认属于DEFAULT_JOB_CLASS。至于说如何查询创建的jobs属于哪个Job Class,还用说吗,*_SCHEDULER_JOBS视图中的JOB_CLASS列呗。

2、 管理Job Classes

  DBMS_SCHEDULER.SET_ATTRIBUTE 过程大家应当还记的,前面的小节中演示中使用该过程,修改job的属性,实际上SET_ATTRIBUTE也同样可以用来修改Job Class的属性,操作方法与修改job属性完全相同,只不过作用函概的范围更广,修改Job Class后,该Job Class下属的所有job属性都会被级联修改(当前正运行的不会立刻生效,将等到下次运行时生效)。

  例如:修改刚刚创建的MY_FIRST_JC的日志保存时间:

JSSWEB> EXEC DBMS_SCHEDULER.SET_ATTRIBUTE(¨SYS.MY_FIRST_JC¨,¨LOG_HISTORY¨,¨30¨);

  • PL/SQL procedure successfully completed.
  • 提示:Job Class可被修改的属性,即创建时可选择指定的那5个属性。

3、 删除Job Classes

  DBMS_SCHEDULER 包提供了DROP_JOB_CLASS过程,用来删除Job Classes。该过程调用非常简单,例如,删除刚刚创建的MY_FIRST_JC,执行命令如下:

JSSWEB> EXEC DBMS_SCHEDULER.DROP_JOB_CLASS(¨MY_FIRST_JC¨);

  • PL/SQL procedure successfully completed.

  如果有多个Job Classes需要删除,并不需要多次执行DROP_JOB_CLASS,只需要在为该过程指定值时,参数值间以逗号分隔即可。

七、使用Windows

  此Windows非彼Windows,通常说的Windows是指盖首富的操作系统,而此处所说的Windows,是指SCHEDULER特性中的一个子项。在SCHEDULER中,WINDOW对应的是一个时间窗口的概念。

  我们知道普通的jobs是没有运行时间管理地概念的,就是说一个job启动之后,用户只能被动地等待其执行,一直到其执行地任务完成(或DBA手动kill对应进程),在此期间,执行的job将与其它活动的进程共同竞争当前系统中的资源。对于大型数据库系统,系统资源那可是相当宝贵的无形资产哪,企能谁说用就用、想什么时候用就什么时候用,没点儿计划没点儿节制这还了得。你还别说,在9i之前,还真就是这么回事儿,谁想用就用,谁也管不了,其中表示最甚的就是job。你是否想起了Job Classes,没错定义Job Classes确实可以控制job能够使用的资源,不过单单使用Job Classes并不能灵活的控制job在合适的时间使用适当的资源。进入10g之后,SCHEDULER中提供了WINDOW,事情终于有了缓解。

  WINDOW 可以指定一个时间窗口,在此期间,通过与Job Classes的搭配组合,能够有效控制job执行时支配(使用)的资源。比如说job通常是在凌晨服务器负载较低时执行,那么就可以通过WINDOW设置在此期间,允许jobs使用更多的系统资源,而到了工作时间后,如果job仍未执行完成,为其分配另一个有限的资源,以尽可能降低job执行占用的资源对其它业务的影响。

1、创建Window

  创建Window有一个专门的过程:DBMS_SCHEDULER.CREATE_WINDOW进行处理,该过程有两种调用方式,如下:

-- 基于SCHEDULE

DBMS_SCHEDULER.CREATE_WINDOW (

   window_name             IN VARCHAR2,

   resource_plan           IN VARCHAR2,

   schedule_name           IN VARCHAR2,

   duration                IN INTERVAL DAY TO SECOND,

   window_priority         IN VARCHAR2                 DEFAULT ¨LOW¨,

   comments                IN VARCHAR2                 DEFAULT NULL);

-- 基于定义的调度

DBMS_SCHEDULER.CREATE_WINDOW (

   window_name             IN VARCHAR2,

   resource_plan           IN VARCHAR2,

   start_date              IN TIMESTAMP WITH TIME ZONE DEFAULT NULL,

   repeat_interval         IN VARCHAR2,

   end_date                IN TIMESTAMP WITH TIME ZONE DEFAULT NULL,

   duration                IN INTERVAL DAY TO SECOND,

   window_priority         IN VARCHAR2                 DEFAULT ¨LOW¨,

  •    comments                IN VARCHAR2                 DEFAULT NULL);

  刨开那些看着眼熟的,已经认识的,看参数名就知道其所代表含义的之外,下列几个参数可能需要关注:

  • Resource_plan :这一参数用来指定要使用的资源使用计划,当打开WINDOW时,就会自动按照指定的资源使用计划中的设置分配资源,当WINDOW关闭时(没错,window是会关闭的,要不怎么说有效控制资源的使用情况泥),系统会自动切换回适当资源计划。这个参数在执行过程时甚至可以指定为NULL或空值¨¨,当设置为NULL时,就表示使用默认的资源计划,当设置为空值¨¨时,表示禁用资源使用计划。
  • Duration :指定WINDOW的有效期,比如说指定为interval ¨5¨ hour就表示5个小时,该参数在执行过程时必须指定参数值,否则创建会报错。
  • Window_priority :该参数用来指定WINDOW的优先级。因为在相同时间只有一个WINDOW有效,因此如果在创建WINDOW时发现重叠的情况,ORACLE就需要根据这一参数指定的规则,来确定优先级,说白了就是先把资源给谁用,这一参数有两个可选值:HIGH或LOW,默认值为LOW。

  正如前面CREATE_WINDOW过程语法结构显示的那样,调用该过程有两种方式,差异就在于是指定现有定义好的调度SCHEDULE,还是在执行过程时指定调度,目标和实现的功能都是相同的,这里仅做示例,咱就挑个最复杂的方式吧,执行过程时指定调度,执行脚本如下:

SQL> begin

  2    dbms_scheduler.create_window(window_name     => ¨my_first_wd1¨,

  3                                 resource_plan   => null,

  4                                 start_date      => sysdate,

  5                                 repeat_interval => ¨FREQ=DAILY; INTERVAL=5¨,

  6                                 duration        => interval ¨1¨ hour);

  7  end;

  8  /

  • PL/SQL procedure successfully completed.

  查询当前拥有的WINDOW,可以通过*_SCHEDULER_WINDOWS视图(注意只有DBA和ALL,没有USER,因为所有定义的WINDOW都属于SYS用户)。除了*_SCHEDULER_WINDOWS视图显示当前所有WINDOW外,还有:

  • *_SCHEDULER_WINDOW_DETAILS 视图:显示WINDOW的详细信息;
  • *_SCHEDULER_WINDOW_LOG 视图:显示WINDOW的日志,比如打开和关闭;

2、管理Window

  通过前面那些SCHEDULER对象的学习,相当大家已经了解了ORACLE SCHEDULER中对象的特点,对于多数对象的管理,不外乎下列几种:

  • 修改对象属性,使用SET_ATTRIBUTE过程;

SQL> exec dbms_scheduler.set_attribute(¨sys.my_first_wd1¨,¨start_date¨,sysdate+1);

  • PL/SQL procedure successfully completed.
  • ENABLE 对象,使用ENABLE过程;

SQL> exec dbms_scheduler.enable(¨sys.my_first_wd1¨);

  • PL/SQL procedure successfully completed.
  • DISABLE 对象,使用DISABLE过程;

SQL> exec dbms_scheduler.disable(¨sys.my_first_wd1¨);

  • PL/SQL procedure successfully completed.
  • 删除对象,使用DROP_WINDOW过程;

SQL> exec dbms_scheduler.drop_window(¨sys.my_first_wd1¨);

  • PL/SQL procedure successfully completed.

  除此之外呢,对于WINDOW对象来说,由于其特殊作用,又有:

  • 手动打开WINDOW,使用OPEN_WINDOW过程;

  注意WINDOW是依赖于其调度的,因此在手动打开WINDOW时,必须为其指定duration属性:

SQL> exec dbms_scheduler.open_window(¨sys.my_first_wd1¨,interval ¨1¨ hour);;

  • PL/SQL procedure successfully completed.
  • 手动关闭WINDOW,使用CLOSE_WINDOW过程;

SQL> exec dbms_scheduler.close_window(¨sys.my_first_wd1¨);

  • PL/SQL procedure successfully completed.

  关闭和打开WINDOW,都会记录日志,大家可以通过*_SCHEDULER_WINDOW_LOG视图中获取这部分信息。

3、关于WINDOW GROUP

  除了WINDOW外,还有一个与WINDOW有关系的叫WINDOW GROUP,一个WINDOW GROUP可能包 含多个WINDOW。使用WINDOW GROUP的本意是这样的,假如说某个job执行的时间比较长,甚至全天24小时都在执行,对于这类job,单个WINDOW很难有效调整其资源占用,这时间呢,就可以通过设置一个WINDOW GROUP,该WINDOW GROUP中包含了多个WINDOW,每个WINDOW分别负责不同时间点时的资源使用计划。

  然后在创建JOB时,指定schedule_name参数为WINDOW GROUP的名称(想不到SCHEDULE_NAME还能指定为WINDOW GROUP哪,其实何止WINDOW GROUP,还可以直接指定成WINDOW哪),这样,就可以通过很简单的方式,将job与window联系在一起了。

  WINDOW GROUP 的创建和管理与前面介绍的方式极其相似:

  • 创建,使用CREATE_WINDOW_GROUP过程;
  • 删除,使用DROP_WINDOW_GROUP过程;
  • 添加WINDOW成员,使用ADD_WINDOW_GROUP_MEMBER过程;
  • 删除WINDOW成员,使用REMOVE_WINDOW_GROUP_MEMBER过程;
  • 启用,使用ENABLE过程;
  • 禁用,使用DISABLE过程;

  这些过程的调用方式也都非常简单,不多说了,我忒忙,感兴趣的朋友不妨自行尝试。

猜你喜欢

转载自blog.csdn.net/viviliving/article/details/88223090