天天看點

Oracle 10g Scheduler 特性 Oracle 10g Scheduler 特性

Oracle 10g Scheduler 特性

本文轉自: http://www.cnblogs.com/AlexSky/archive/2012/07/26/2609837.html

Oracle 10g Scheduler 特性 

在10g 環境中,ORACLE 建議使用Scheduler 替換普通的job,來管理任務的執行。其實,将Scheduler 描述成管理job 的工具已經太過片面了,10G版本中新增的Scheduler 絕不僅僅是建立任務這麼簡單.

一. 使用Jobs

所謂JOBS,其實就是Scheduler 管理的一個(或多個)任務的執行排程。

1.1 建立Jobs

通過DBMS_SCHEDULER 包來建立Jobs,是使用其CREATE_JOB 過程。在建立Job 時,使用者可以指定要執行的任務,排程資訊(啥時候執行,執行周期,終止日期等)以及其它一些任務相關的屬性。CREATE_JOB 過程調用還是比較簡單的,例如:

create table TEST (id number);

CREATE OR REPLACE PROCEDURE IT

AS

BEGIN

insert into TEST VALUES(1);

END;

SQL> BEGIN

DBMS_SCHEDULER.CREATE_JOB (

job_name => 'JobTest',

job_type => 'STORED_PROCEDURE',

job_action => 'SYSTEM.IT',

start_date => sysdate,

repeat_interval => 'FREQ=MINUTELY;INTERVAL=10');

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。

   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') TM,repeat_interval,enabled,state from user_scheduler_jobs;

JOB_NAME   JOB_TYPE         JOB_ACTION TM         REPEAT_INTERVAL           ENABL STATE

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

JOBTEST    STORED_PROCEDURE SYSTEM.IT  2009-09-25 FREQ=MINUTELY;INTERVAL=10  FALSE DISABLED

不過,細心的盆友可能會發現,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('JOBTEST');

PL/SQL procedure successfully completed.

1.2.2 禁用Jobs

DBMS_SCHEDULER.ENABLE 僅用來将JOB(其實不僅僅對JOB 有效,對于CHAIN、PROGRAM 等也有效)的啟用狀态置為TRUE。如果想将其啟用狀态置為FALSE?簡單,還有一個與該功能對應的過程:

DBMS_SCHEDULER.DISABLE,例如:

JSSWEB> exec dbms_scheduler.disable('JOBTEST');

PL/SQL procedure successfully completed.

這兩個過程僅用來重置對象的狀态,是以均可以無限次執行,即使執行時對象已經被置為要指定的狀态。

1.2.3 修改Jobs

由于JOB 的屬性衆多,難免時不時的可能會遇到需要修改的情況,比如說前面建立JOB 時不小心,指定要

執行的過程名輸入錯誤(完全有可能,CREATE_JOB 在建立時不會自動檢查指定的過程是否有效,從這方面考慮,

SCHEDULER 不如普通JOB 嚴謹哪),這種情況下就必然涉及到對JOB 的修改(或者說重定義),沒問題,

DBMS_SCHEDULER 包中專門提供了一個過程SET_ATTRIBUTE,可以用來修改任務的屬性值。

例如,修改剛剛建立的JOB:INSERT_TEST_TBL 執行的過程,執行語句如下:

JSSWEB> exec dbms_scheduler.set_attribute('JobTest','JOB_ACTION','SYSTEM.IT');

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:JOBTEST:

JSSWEB> exec dbms_scheduler.run_job('JOBTEST');

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 過程,例如:

JSSWEB> exec dbms_scheduler.stop_job('JOBTEST');

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 過程即可,例如:

JSSWEB> exec dbms_scheduler.drop_job('JOBTEST');

PL/SQL procedure successfully completed

删除jobs 并不是修改該job 中某個字段的标記值,而是直接删除其在資料字典中的字義,是以被删除的job

如果未來發現仍然需要,隻能重建,而無法通過其它方式快速恢複。不過,删除jobs 的操作,并不會級聯删除

這些job 曾經執行過的日志資訊。

二、使用Programs

進入10g 版本之後,可以在ORACLE 中執行作業系統指令,或是ORACLE 資料庫外的應用,因為有了DBMS_SCHEDULER,因為有了PROGRAM。

2.1 建立Programs

Scheduler 中的Program 對象并不是正常意義上的"程式"或"應用",而就是一個"對象",由DBA 定義的,具

有執行某項功能的特殊對象。Program 中實際執行的操作可以分為下列三種類型:

   PL/SQL BLOCK:标準的pl/sql 代碼塊;

   STORED PROCEDURE:編譯好的PL/SQL 存儲過程,或者Java 存儲過程,以及外部的子程式;

   EXECUTEABLE:ORACLE 資料庫之外的應用,比如作業系統指令等等。

建立Programs 使用DBMS_SCHEDULER.CREATE_PROGRAM 過程,該過程支援的參數如下:

SQL> 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

COMMENTS 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 指令,操作如下:

SQL> BEGIN

DBMS_SCHEDULER.CREATE_PROGRAM (

program_name => 'IPCONFIG',

program_action => 'C:\WINDOWS\system32\ipconfig.exe',

program_type => 'EXECUTABLE',

enabled => TRUE);

END;

/

PL/SQL procedure successfully completed.

2.2 管理Programs

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

from user_scheduler_programs;

由于前面建立program 時並未指定NUMBER_OF_ARGUMENTS 的值,是以我們這裡需要首先修改該值為

一個非0 值,操作如下:

SQL> exec dbms_scheduler.set_attribute('IPCONFIG','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('IPCONFIG');

PL/SQL procedure successfully completed.

另外,如果希望将program 置為enabled 狀态,執行DBMS_SCHEDULER.ENABLE 過程即可,這裡不再例舉。

接下來,就可以為剛剛建立的IPCONFIG添加路徑參數,操作如下:

SQL> BEGIN

DBMS_SCHEDULER.DEFINE_PROGRAM_ARGUMENT (

program_name => 'IPCONFIG',

argument_position => 1,

argument_name => 'dirpath',

argument_type => 'VARCHAR2',

default_value => 'C:\');

END;

/

PL/SQL procedure successfully completed.

exec DBMS_SCHEDULER.ENABLE('IPCONFIG');

查詢為program 定義的參數,可以通過USER_SCHEDULER_PROGRAM_ARGS 視圖,例如:

SQL> select program_name,argument_name,argument_position,argument_type

default_value from user_scheduler_program_args;

删除program 的argument 操作也很簡單,使用DROP_PROGRAM_ARGUMENT 過程即可,例如:

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

PL/SQL procedure successfully completed.

該過程第一個參數指定program 名稱,第二個參數指定定義的argument 名稱,當然此處也可以指定argument

的位置,即前例視圖傳回結果中的ARGUMENT_POSITION 列值。

要删除program 的話就更簡單了,使用DROP_PROGRAM 過程即可,例如:

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

PL/SQL procedure successfully completed.

當然啦,删除program 的同時,也會删除該program 對應的所有arguments。

實際上SCHEDULER 中建立job 時,也可以指定執行外部的程式。SCHEDULER 中的Job 更像是之前版本

繼承過來的JOBS,隻不過10g 中SCHEDULER 管理的JOBS 功能更加強大。Programs 與Jobs 不同的是,Jobs

是定義好的,定時執行的任務,而Programs 則是定義好的,等待被執行的對象。

三、使用Schedules

10g 中新推出的SCHEDULER 可能确實會讓很多初接觸的朋友感覺暈頭暈腦,相比之前的jobs,

SCHEDULER 中新增的概念太多。比如說jobs,仍然可以了解成之前版本中的jobs,不過功能更加強大,比如說program,指的是運作的程式(把要做什麼單提出來了),比如說schedule,我将其翻譯為排程,定義執行的

頻率或者說周期。

3.1 建立和管理Schedules

Schedule,中文直譯的話應該了解成排程,從名字來看,它是一個邏輯實體,就是說當建立了schedule 之後,資料庫中就肯定存在這一對象,隻不過這一對象是用來描述job 的執行周期。

建立schedule 可以通過DBMS_SCHEDULER.CREATE_SCHEDULE 過程,該過程支援的參數如下:

SQL>desc dbms_scheduler

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

DBMS_SCHEDULER.CREATE_SCHEDULE (

schedule_name => 'MySchedule',

start_date => SYSDATE,

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

comments => 'Every 1 weeks');

END;

/

PL/SQL procedure successfully completed.

查詢目前已經建立的schedules,可以通過*_SCHEDULER_SCHEDULES 視圖(含DBA_,ALL_,USER_),例如,檢視目前使用者擁有的schedules,執行語句如下:

SQL> select schedule_name,repeat_interval from user_scheduler_schedules;

如果要修改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 版本中SCHEDULER 将JOB分成了多個部分,program 負責做什麼,schedule 負責啥時候做,job 就簡單了,一個字:做。

前面幾個小節,已經分别示範了建立管理Jobs,建立管理Programs 以及建立和管理Schedules,下面我

們通過執行個體來示範,如何建立通過schedule 排程program 的執行的job 吧。

1. 我們用前面建立的Program: IPCONFIG,執行作業系統指令ipconfig。

2. 用我們剛建立的schedule:MySchedule

3. 建立job,按照指定的schedule,執行program,操作如下:

SQL> BEGIN

DBMS_SCHEDULER.CREATE_JOB (

job_name => 'ExecCmd',

program_name => 'IPCONFIG',

schedule_name => 'MySchedule',

enabled => true);

END;

/

PL/SQL procedure successfully completed.

建立job 時,start_date,repeat_interval,job_action 等均無須指定,因為這些參數将由program 和schedule 來控

制。

這樣,操作完成後,ORACLE 就會自動定時(目前設定為每周執行一次)program 中定義的操作。

要檢視目前的執行情況,通過*_scheduler_job_run_details 即可查詢(*_scheduler_job_log 也可以,不過該視

圖中資訊不如detail 中全面)。例如,檢視剛剛建立的"ExecCmd"任務的執行情況,執行指令如下:

SQL> select log_id,log_date,status,additional_info from user_scheduler_job_run_details where job_name = 'ExecCmd';

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

daynum = 1 through 5

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

DBMS_SCHEDULER.SET_ATTRIBUTE('JOBTEST', 'raise_events',DBMS_SCHEDULER.JOB_ALL_EVENTS);

END;

/

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 隊列。

例如,手動執行一次JOBTEST,看看是否向隊列中記錄資訊,操作如下:

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

PL/SQL procedure successfully completed.

執行下列腳本,出隊資料:

SQL> set serveroutput on

SQL> DECLARE

l_dequeue_options DBMS_AQ.dequeue_options_t;

l_message_properties DBMS_AQ.message_properties_t;

l_message_handle RAW(16);

l_queue_msg sys.scheduler$_event_info;

BEGIN

l_dequeue_options.consumer_name := 'TEST';

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

dequeue_options => l_dequeue_options,

message_properties => l_message_properties,

payload => l_queue_msg,

msgid => l_message_handle);

COMMIT;

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

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

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

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

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

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

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

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

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

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

END;

/

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:JOBTEST執行一次至少會向隊列中插入兩條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 Test_type1 as object

2 (

3 event_type VARCHAR2(10),

4 object_owner VARCHAR2(30),

5 object_name VARCHAR2(30)

6 );

7 /

Type created.

SQL> begin

2 dbms_aqadm.create_queue_table(

3 queue_table => 'my_queue_tbl1',

4 queue_payload_type => 'Test_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 => 'SYSTEM.IT',

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 仍然執行IT 過程。

通過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

v_Message Test_type1;

v_EnqueueOptions dbms_aq.enqueue_options_t;

v_MessageProperties dbms_aq.message_properties_t;

v_msg_handle raw(16);

begin

v_message := jss_type1('OP_SELECT', user, 'tmpObj');

dbms_aq.enqueue(queue_name => 'event_t1',

enqueue_options => v_enqueueOptions,

message_properties => v_messageproperties,

payload => v_message,

msgid => v_msg_handle);

commit;

end;

/

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

v_Message jss_type1;

v_EnqueueOptions dbms_aq.enqueue_options_t;

v_MessageProperties dbms_aq.message_properties_t;

v_msg_handle raw(16);

begin

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

dbms_aq.enqueue(queue_name => 'event_t1',

enqueue_options => v_enqueueOptions,

message_properties => v_messageproperties,

payload => v_message,

msgid => v_msg_handle);

commit;

end;

/

再次檢視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) 可以被視做一組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 對象建立之後,要做的工作其實才剛剛開始。其後,還需要定義ChainSteps 以及Chain rules。

5.1.2 建立Chain Step

Chain Steps 就是用來指定CHAIN 執行的操作及執行步驟, 建立CHAIN STEP 是通過

DBMS_SCHEDULER.DEFINE_CHAIN_STEP 過程進行,例如,為剛剛建立的my_chain1 添加一個step,執行操作如下:

SQL> begin

DBMS_SCHEDULER.DEFINE_CHAIN_STEP (

chain_name => 'my_chain1',

step_name => 'my_step1',

program_name => 'p_p1');

end;

/

PL/SQL procedure successfully completed.

Chain Steps 即可以調用PROGRAM(注意是program,不是procedure,當然program 中可以定義執行procedure),也可以調用EVENT,甚至調用其它CHAIN(這就叫嵌套CHAIN)。

下面接着為my_chain1 添加兩個step,操作如下:

SQL> begin

DBMS_SCHEDULER.DEFINE_CHAIN_STEP (

chain_name => 'my_chain1',

step_name => 'my_step2',

program_name => 'p_p2');

DBMS_SCHEDULER.DEFINE_CHAIN_STEP (

chain_name => 'my_chain1',

step_name => 'my_step3',

program_name => 'p_p3');

end;

/

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

DBMS_SCHEDULER.DEFINE_CHAIN_RULE (

chain_name => 'my_chain1',

condition => 'TRUE',

action => 'START my_step1',

rule_name => 'my_rule1');

DBMS_SCHEDULER.DEFINE_CHAIN_RULE (

chain_name => 'my_chain1',

condition => 'my_step1 completed',

action => 'START my_step2',

rule_name => 'my_rule2');

DBMS_SCHEDULER.DEFINE_CHAIN_RULE (

chain_name => 'my_chain1',

condition => 'my_step2 completed',

action => 'end 0',

rule_name => 'my_rule3');

END;

/

PL/SQL procedure successfully completed.

5.1.4 運作Chains

最後,來運作一下建立的my_chain1 吧,手動運作CHAIN 是通過DBMS_SCHEDULER.RUN_CHAIN 過程,

例如:

SQL> BEGIN

DBMS_SCHEDULER.RUN_CHAIN (

chain_name => 'my_chain1',

start_steps => 'my_step1');

END;

/

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

DBMS_SCHEDULER.CREATE_JOB (

job_name => 'chain_job_1',

job_type => 'CHAIN',

job_action => 'my_chain1',

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

enabled => TRUE);

END;

/

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,該過程支援的參數如下:

SQL> 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:指定日志記錄的級别,有下列三種級别:

   DBMS_SCHEDULER.LOGGING_OFF:關閉日志記錄功能;

   DBMS_SCHEDULER.LOGGING_RUNS:對該Job Class 下所有任務的運作資訊進行記錄;

   DBMS_SCHEDULER.LOGGING_FULL:記錄該Job Class 下任務的所有相關資訊,不僅有任務的運作情況,甚至連任務的建立、修改等也均将記入日志。

   LOG_HISTORY:指定日志記錄的時間,以天為機關,比如指定LOG_HISTORY 參數值為90,就表示日志資訊保留最近90 天的内容。

   COMMENTS:指定注釋資訊。

上述各個參數,除了LOG_CLASS_NAME 參數為必選參外,其它均為可選參數,例如:

SQL> EXEC DBMS_SCHEDULER.CREATE_JOB_CLASS('my_first_jc');

PL/SQL procedure successfully completed

查詢系統中已經存在的Job Classes .可以通過DBA_SCHEDULER_JOB_CLASSES視圖( 或ALL_SCHEDULER_JOB_CLASS 視圖)

當建立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 的日志儲存時間:

SQL> 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

dbms_scheduler.create_window(

window_name => 'my_first_wd1',

resource_plan => null,

start_date => sysdate,

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

duration => interval '1' hour);

end;

/

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、關于WINDOWGROUP

除了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 過程;

這些過程的調用方式也都非常簡單,這裡就不着重示範了,感興趣的朋友不妨自行嘗試。

本文來自CSDN部落格,轉載請标明出處:http://blog.csdn.net/tianlesoftware/archive/2009/10/22/4715218.aspx