Oracle scheduler job管理

0、參考資料

oracle 10g以後的scheduler非常強大,完全替代了之前的dbms_job,可以調度的任務類型非常多。本篇文檔整理自網絡。

參考樣例:E:\1@Repository IT\1.0@Oracle\1.0.0@基本日常管理\調度任務管理

數據庫的自動管理任務autotask除外

Oracle Database Administrator’s Guide -> Database Resource Management and Task Scheduling

1、使用scheduler job

scheduler job 其實就是scheduler 管理的一個或者多個任務的執行調度。

1.1、創建scheduler job

通過DBMS_SCHEDULER 包來創建Jobs,是使用其CREATE_JOB 過程。在創建Job 時,用戶可以指定要執行的任務,調度信息(什麼時候執行,執行週期,終止日期等)以及其它一些任務相關的屬性。例如:

BEGIN
DBMS_SCHEDULER.CREATE_JOB (
job_name => 'scott.JobTest',
job_type => 'STORED_PROCEDURE',
job_action => 'scott.procedure',
start_date => sysdate,
repeat_interval => 'FREQ=MINUTELY;INTERVAL=10',
enabled         => true,
comments        => 'GET TOPDBTIME AWR SCHEDULER');
END;
/

用戶可以創建其它SCHEMA 下的JOB,只需要在指定JOB_NAME 時,按照schema.job_name 的格式即可。這種情況下創建的JOB,其CREATED 與OWNER 有可能並不相同。當使用CREATE_JOB 過程創建JOB 時,可指定的參數值很多,只不過多數情況下用戶僅指定部分參數即可滿足需求。具體可以指定哪些參數可以查看DBMS_SCHEDULER.CREATE_JOB包的定義。

參數含義說明:

JOB_NAME:指定任務的名稱,必選值,注意要確保指定的名稱唯一。
JOB_TYPE:任務執行的操作類型,必選值,有下列幾個可選值:
(1) PLSQL_BLOCK:表示任務執行的是一個PL/SQL 匿名塊。
(2)STORED_PROCEDURE:表示任務執行的是ORACLE 過程(含L/SQL PROCEDURE 和JAVA PROCEDURE),本例中正是指定這一參數值。
(3)EXECUTABLE:表示任務執行的是一個外部程序,比如說操作系統命令。
(4)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 兩個關鍵字。
(1)FREQ 關鍵字用來指定間隔的時間週期,可選參數有:YEARLY,MONTHLY,WEEKLY,DAILY,HOURLY,MINUTELY,and SECONDLY,分別表示年、月、周、日、時、分、秒等單位。
(2)INTERVAL 關鍵字用來指定間隔的頻繁,可指定的值的範圍從1-99。
例如:REPEAT_INTERVAL=>'FREQ=DAILY;INTERVAL=1';表示每天執行一次,如果將INTERVAL 改爲7 就表示每7 天執行一次,效果等同於FREQ=WEEKLY;INTERVAL=1。
一般來說,使用DBMS_SCHEDULER.CREATE_JOB 創建一個JOB,至少需要指定上述參數中的前3 項。除此之外,還可以在CREATE_JOB 時,指定下列參數:
(1)NUMBER_OF_ARGUMENTS:指定該JOB 執行時需要附帶的參數的數量,默認值爲0,注意當JOB_TYPE 列值爲PLSQL_BLOCK 或CHAIN 時,本參數必須設置爲0,因爲上述兩種情況下不支持附帶參數。
(2)END_DATE:指定任務的過期時間,默認值爲NULL。任務過期後,任務的STATE 將自動被修改爲COMPLETED,ENABLED 被置爲FALSE。如果該參數設置爲空的話,表示該任務永不過期,將一直按照    REPEAT_INTERVAL 參數設置的週期重複執行,直到達到設置的MAX_RUNS 或MAX_FAILURES 值。
(3)JOB_CLASS:指定任務關聯的CLASS,默認值爲DEFAULT_JOB_CLASS。
(4)ENABLED:指定任務是否啓用,默認值爲FALSE。FALSE 狀態表示該任務並不會被執行,除非被用戶手動調用,或者用戶將該任務的狀態修改爲TRUE。
(5)AUTO_DROP:當該標誌被置爲TRUE 時,ORACLE 會在滿足條件時自動刪除創建的任務
1)任務已過期;
2)任務最大運行次數已達MAX_RUNS 的設置值;
3)任務未指定REPEAT_INTERVAL 參數,僅運行一次;
該參數的默認值即爲TRUE。用戶在執行CREATE_JOB 過程時可以手動將該標誌指定爲FALSE,當參數值設置爲FALSE 時,即使滿足上述提到的條件任務也不會被自動刪除,這種情況下,唯一能夠導致任務被刪除的情況,就是用戶主動調用DROP_JOB 過程。
(6)COMMENTS:設置任務的註釋信息,默認值爲NULL。

上面的例子創建了一個新的JOB,不過這個JOB 與普通JOB 不同,此時查詢USER_JOBS 視圖是查不到剛剛創建的JOB 的信息,因爲這個JOB 是SCHEDULER 管理的JOB。要查詢SCHEDULER 管理的JOBS,應該通過user_scheduler_jobs(all_scheduler_jobs,dba_scheduler_jobs也可以 ),例如:

select job_name,job_type,job_action,to_char(start_date,'yyyy-mm-ddhh24:mi:ss') TM,repeat_interval,enabled,state from user_scheduler_jobs;

1.2、查詢scheduler job

select * from dba_scheduler_jobs;
select * from dba_scheduler_job_log
select * from dba_scheduler_job_run_details
select * from dba_scheduler_running_jobs

1.3、管理scheduler job

啓用&禁用scheduler job

exec dbms_scheduler.enable('SCOTT.JOBTEST');
exec dbms_scheduler.disable('SCOTT.JOBTEST');

修改scheduler job
對scheduler job的修改(或者說重定義),DBMS_SCHEDULER 包中專門提供了一個過程SET_ATTRIBUTE,可以用來修改任務的屬性值。
執行語句如下,說明:可以參考dbms_scheduler.set_attribute包定義;name,attribute,value這樣的格式,並且一次只能修改一個屬性。

exec dbms_scheduler.set_attribute('jobtest','JOB_ACTION','proc_name');

SET_ATTRIBUTE 過程雖然僅有三個參數,不過能夠修改的屬性值可是不少,以下列舉幾個較常用到的:

(1)LOGGING_LEVEL:指定對jobs 執行情況記錄的日誌信息級別。SCHEDULER 管理的JOB 對任務的執行情況專門進行了記錄,同時用戶還可以選擇日誌中記錄信息的級別,有下列三種選擇:
1)DBMS_SCHEDULER.LOGGING_OFF:關閉日誌記錄功能;
2) DBMS_SCHEDULER.LOGGING_RUNS:對任務的運行信息進行記錄;
3) DBMS_SCHEDULER.LOGGING_FULL:記錄任務所有相關信息,不僅有任務的運行情況,甚至連任務的創建、修改等也均將記入日誌。
提示: 查看scheduler 管理的job ,可以通過user_scheduler_job_log 和user_scheduler_job_run_details 兩個視圖中查詢。
(2) RESTARTABLE:指定jobs 運行出錯後,是否能夠適時重啓創建任務時如未明確指定,本參數默認情況下設置爲FALSE,如果設置爲TRUE,就表示當任務運行時出錯,下次運行時間點到達時仍會啓動,並且如果運行仍然出錯,會繼續重新運行,不過如果連接出錯達到6 次,該job 就會停止。
(3) MAX_FAILURES:指定jobs 最大連續出錯次數該參數值可指定的範圍從1-1000000,默認情況下該參數設置爲NULL,表示無限制。達到指定出錯次數後,該job 會被自動disable。
(4) MAX_RUNS:指定jobs 最大運行次數,該參數值可指定的範圍從1-1000000,默認情況下該參數設置爲NULL,表示無限制(只是運行次數無限制,實際job 是否繼續運行,仍受制於end_date 以及max_failures 等參數的設置)。達到指定運行次數後,該job 也將被自動disable,並且狀態會被置爲COMPLETED。
(5) JOB_TYPE:指定job 執行的任務的類型,有四個可選值:'PLSQL_BLOCK','STORED_PROCEDURE','EXECUTABLE',and 'CHAIN'。
(6) JOB_ACTION:指定job 執行的任務.這一參數所指定的值依賴於JOB_TYPE 參數中的值,比如說JOB_TYPE 設置爲'STORED_PROCEDURE',那麼本參數值中指定的一定是ORACLE 中的過程名。
(7) START_DATE:指定job 初次啓動的時間
(8)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 等等。
另外需要注意一點,除了用戶手動創建的jobs 之外,數據庫在運行過程中也有可能自動創建jobs。對於這類jobs 除非必要,否則不建議進行修改。至於如何區分jobs 是用戶創建,還是數據庫自動創建,可以通過*_SCHEDULER_JOBS 視圖的SYSTEM 列來確定,如果該列顯示爲TRUE,則表示由系統創建。

執行&停止scheduler job
雖然說jobs 大多都應該是自動執行,不過經過前面的示例看出,並不是說創建了jobs 它就會自動執行,是否能夠真正自動執行由jobs 自身的多個相關屬性決定。
執行job可以使用DBMS_SCHEDULER 包手動調用jobs並執行。如:

  exec dbms_scheduler.run_job('JOBTEST');

jobs 每執行一次,無論成功或失敗,均會在*_scheduler_job_log 中生成一條對應的記錄(前提是logging_level 屬性值未設置爲dbms_scheduler.logging_off),同時,用戶也可以通過使用 *_scheduler_job_run_details 視圖查詢job 執行的詳細信息。
停止job 可以使用DMBS_SCHEDULER.STOP_JOB 過程,例如:

exec dbms_scheduler.stop_job('JOBTEST');

select ‘exec dbms_scheduler.stop_job(’||’’’||job_name||’’’||’);’ jobname from dba_scheduler_running_jobs;

注意,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

刪除創建的job 就比較簡單了,直接執行dbms_scheduler.drop_job 過程即可,例如:

 exec dbms_scheduler.drop_job('JOBTEST');

刪除jobs 並不是修改該job 中某個字段的標記值,而是直接刪除其在數據字典中的字義,因此被刪除的job如果未來發現仍然需要,只能重建,而無法通過其它方式快速恢復。不過,刪除jobs 的操作,並不會級聯刪除這些job 曾經執行過的日誌信息。

2、使用Programs

oracle 10g 版本以後,可以在ORACLE 中執行操作系統命令,或是ORACLE 數據庫外的應用,因爲有了DBMS_SCHEDULER,因爲有了PROGRAM。

2.1、 創建Programs

Scheduler 中的Program 對象並不是常規意義上的"程序"或"應用",而就是一個"對象",由DBA 定義的,具有執行某項功能的特殊對象。Program 中實際執行的操作可以分爲下列三種類型:

(1) PL/SQL BLOCK:標準的pl/sql 代碼塊;
(2) STORED PROCEDURE:編譯好的PL/SQL 存儲過程,或者Java 存儲過程,以及外部的子程序;
(3) EXECUTEABLE:ORACLE 數據庫之外的應用,比如操作系統命令等等。

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

(1) PROGRAM_NAME:指定一個program 名稱;
(2) PROGRAM_TYPE:Program 的類型,如前文中所述,Program 支持三種類型;
(3) PROGRAM_ACTION:實際執行的操作,應與前面PROGRAM_TYPE 參數關聯使用。比如說前面指定了PROGRAM_TYPE 爲"PLSQL_BLOCK",那麼此處要執行的action 就應當是一段標準的pl/sql 代碼。如果前面指定PROGRAM_TYPE 爲"STORED_PROCEDURE",那麼此處要執行的action 就應當是ORACLE 中定義好的存儲過程(含Java 存儲過程),如果前面指定PROGRAM_TYPE 爲"EXECUTABLE",那麼此處就應該指定外部命令的命令行信息(含路徑信息);
(4)NUMBER_OF_ARGUMENTS:指定支持的參數個數,默認值爲0 即沒有參數。每個program 最多能夠支持255 個參數,注意如果PROGRAM_TYPE 設置爲PLSQL_BLOCK,那麼本參數自動忽略;
(5) ENABLED:指定是否將創建的program 置爲有效狀態,默認情況下爲false。
(6) COMMENTS:這個不用再說了吧,註釋信息。

下面實際操作一下看看,PL/SQL 或PROCEDURE 沒有挑戰(ORACLE 中直接即可調用),咱們創建一下program,直接調用操作系統中的ipconfig命令,操作如下:

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);

另外需要注意, program 的NUMBER_OF_ARGUMENTS 參數不是說想改就能改的,正常情況下該處理必須是在program 處於enabled 之前確認完畢,否則會觸發ORA-27465 錯誤,因此要修改program 的參數之前,必須首先確保要修改program 的enabled 狀態爲false。
那麼對於已經處於enabled 狀態的program,在修改之前要修改其狀態。如:

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

如果想啓用,執行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;
/ 
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 則是定義好的,等待被執行的對象。

3、使用Schedules

3.1、創建和管理Schedules

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

各參數分別代表含意如下:

(1)SCHEDULE_NAME:指定schedule 名稱,注意名稱不能重複。
(2) START_DATE:指定該調度的開始時間,可爲空,當爲空時表示該調度暫不起用。
(3) REPEAT_INTERVAL:指定調度的執行頻率或週期。
(4) END_DATE:指定調度的結束時間,可爲空,爲空時就表示該調度將一直進行。
(5) COMMENTS:註釋信息 

Schedules 中的REPEAT_INTERVAL 參數和Jobs 中的REPEAT_INTERVAL參數功能完全相同,甚至參數格式也一模一樣。其中最重要的是FREQ 和INTERVAL 兩個關鍵字。

(1) FREQ 關鍵字用來指定間隔的時間週期,可選參數有:YEARLY, MONTHLY, WEEKLY, DAILY,HOURLY, MINUTELY, and SECONDLY,分別表示年、月、周、日、時、分、秒等單位。
(2) 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;
/

查詢當前已經創建的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。下面我們通過實例來演示,如何創建通過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;
/

創建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 /* 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';

**注意:**SCHEDULER 中的REPEAT_INTERVAL 也完全可以按照以前Job方式設置, REPEAT_INTERVAL實際上是指定週期,直接指定一個時間值,當然也是週期。
比如說,設置任務每天執行一次,也可以設置REPEAT_INTERVAL 參數值如下:

REPEAT_INTERVAL => 'trunc(sysdate)+1'

又比如設置任務每週執行一次:

REPEAT_INTERVAL => 'trunc(sysdate)+7'

不過需要注意,這種方式僅用於創建SCHEDULER 中jobs 時使用,不能用於schedule。

4、使用Events

SCHEDULER 中有兩種觸發EVENT 的情況:
(1) Scheduler 觸發的Events
Scheduler 中觸發的Events,一般是說當前schduler 中job 的狀態發生修改,類似job 啓動,或者運行結束,或者達到運行時間等諸如此類的動作,都能夠拋出一個EVENT,接收到EVENT 的applicate 就可以根據這些信息進行適當的處理。
比如說,由於系統太過於繁忙,超出job 啓動時間後30 分鐘,job 仍然沒能順利啓動,那麼這個時候,Scheduler 就可以拋出一條EVENT 給外部的應用,以便外部應用能夠及時通知DBA,進行處理。
(2) 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 對應的隊列中。

4.1、Scheduler拋出的Events

Scheduler 拋出的Events 一般是指job 狀態改變時觸發的,默認情況下,job 是不觸發Events 的。
Scheduler 中的job 有一個屬性叫raise_events,專門用來設置job 觸發Events 的條件,該屬性在CREATE_JOB時不能執行,因此默認情況下該屬性不會賦值,自然也就不會觸發EVENT。要設置raise_events 屬性,只能是在job 創建完成後,通過SET_ATTRIBUTE 過程修改job 的raise_events 屬性。
例如,修改前面創建的jobtest,啓用raise_events 屬性,執行語句如下:

sql> begin
dbms_scheduler.set_attribute('jobtest', 'raise_events',dbms_scheduler.job_all_events);
end;
/

上述示例中指定的raise_events 屬性的屬性值dbms_scheduler.job_all_events,就是拋出events的觸發條件。
觸發Events 的有下列的類型,分別代表不同的操作:

(1)job_started:JOB 啓動;
(2) job_succeeded:JOB 成功結束;
(3) job_failed:JOB 執行失敗;
(4) job_broken:JOB 被置爲BROKEN 狀態;
(5) job_completed:JOB 達到最大運行次數,或者運行的結束日期;
(6) job_stopped:JOB 被STOP_JOB 過程置爲停止執行的狀態;
(7) job_sch_lim_reached:Job 的schedule 達到限定值;
(8) job_disabled:JOB 被置於DISABLE 狀態;
(9) job_chain_stalled:運行於chain 的JOB 被置於CHAIN_STALLED 狀態;
(10) job_all_events:含上述提到的所有類型;
(11)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

Scheduler 能夠拋出Events 讓外部應用處理,外部的應用也可以拋出Events 讓Scheduler 啓動job 處理,不過並不是任何job 都能夠對外部應用拋出的Events 做出響應,必須在創建jobs 時明確指定響應的事件。可以通過如下參數指定:

(1)queue_spec:指定外部應用拋出的events 消息入隊的隊列名;
(2)event_condition:指定觸發job 啓動的條件,這一參數的參數值在設置時應當基於事件消息的自身屬性,因爲事件消息在入隊時,消息的屬性都是由application 定義的,因此在設置觸發條件時,也應該根據這些屬性值就行設置。

下面,我們就演示創建一個由event 觸發啓動的job,具體的操作步驟如下:

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.

準備工作完成,下面就來創建一個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 的啓動,具體操作如下。
(1)首先要執行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.

(2)執行入隊操作:

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.

(3)查詢隊列表中的數據:

SQL> select user_data from my_queue_tbl1;
USER_DATA(EVENT_TYPE, OBJECT_OWNER, OBJECT_NAME)
---------------------------------------------------------
JSS_TYPE1('OP_SELECT', 'TEST', 'tmpObj')

(4)然後查詢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 條件嗎:
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 錯誤。

5、使用Chains

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

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,也可以調用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

需要注意的是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 對象來說,能夠修改的屬性只有兩個:evaluation_interval 和comments,這兩個參數一般情況下甚至都不會進行設置。如果你碰到了確實需要修改的情況,可以使用DBMS_SCHEDULER.SET_ATTRIBUTE 過程。例如:

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 參數指定:

(1)PAUSE:設置該參數值爲TRUE 時,當step 運行時,其運行狀態就會變更爲PAUSED;
(2) SKIP:設置該參數值爲TRUE 時,當step 滿足運行條件時,並不是執行step 中的program,而是直接跳過,注意當SKIP 參數值設置爲TRUE,並且PAUSE 參數值也被設置爲TRUE,那麼將會以PAUSE 的狀態優先;
(3) 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

例如,刪除之前定義的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 之類),因此無法直接刪除。
這種情況下解決方案有兩種:

(1)手動刪除所有相關的chain_step 和chain_rule,然後再執行chain 的刪除,
(2)附加force 參數並指定參數值爲true,這樣ORACLE 就會自動替你清除所有依賴的對象了。

6、使用Job Classes

Job Classes 相當於創建了一個job 組,DBA 可以將那些具有相同特性的job,統統放到相同的Job Classes中,然後通過對Job Class 應用ORACLE 中的"資源使用計劃"特性,就可以對這些job 執行過程中所需要的資源分配情況進行管理。

6.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:指定日誌記錄的級別,有下列三種級別:
(1)DBMS_SCHEDULER.LOGGING_OFF:關閉日誌記錄功能;
(2) DBMS_SCHEDULER.LOGGING_RUNS:對該Job Class 下所有任務的運行信息進行記錄;
(3) 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 。可以使用*_SCHEDULER_JOBS 視圖中的JOB_CLASS 列查看對應的信息。

6.2、管理Job Classes

DBMS_SCHEDULER.SET_ATTRIBUTE 過程的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 個屬性。

6.3、刪除Job Classes

DBMS_SCHEDULER 包提供了DROP_JOB_CLASS 過程,用來刪除Job Classes。該過程調用非常簡單,例如,刪除剛剛創建的MY_FIRST_JC,執行命令如下:

SQL> EXEC DBMS_SCHEDULER.DROP_JOB_CLASS('MY_FIRST_JC');
PL/SQL procedure successfully completed.

如果有多個Job Classes 需要刪除,並不需要多次執行DROP_JOB_CLASS,只需要在爲該過程指定值時,參數值間以逗號分隔即可。

7、使用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 執行佔用的資源對其它業務的影響。

7.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);

下列幾個參數可能需要關注:
(1)Resource_plan:這一參數用來指定要使用的資源使用計劃,當打開WINDOW 時,就會自動按照指定的資源使用計劃中的設置分配資源,當WINDOW 關閉時,系統會自動切換回適當資源計劃。這個參數在執行過程時甚至可以指定爲NULL 或空值’’,當設置爲NULL 時,就表示使用默認的資源計劃,當設置爲空值’'時,表示禁用資源使用計劃。
(2) Duration:指定WINDOW 的有效期,比如說指定爲interval ‘5’ hour 就表示5 個小時,該參數在執行過程時必須指定參數值,否則創建會報錯。
(3) 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外,還有:

(1)*_SCHEDULER_WINDOW_DETAILS 視圖:顯示WINDOW 的詳細信息;
(2)*_SCHEDULER_WINDOW_LOG 視圖:顯示WINDOW 的日誌,比如打開和關閉;

7.2、管理Window

修改對象屬性,使用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 視圖中獲取這部分信息。

7.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 的創建和管理與前面介紹的方式極其相似:

(1)創建,使用CREATE_WINDOW_GROUP 過程;
(2) 刪除,使用DROP_WINDOW_GROUP 過程;
(3) 添加WINDOW 成員,使用ADD_WINDOW_GROUP_MEMBER 過程;
(4) 刪除WINDOW 成員,使用REMOVE_WINDOW_GROUP_MEMBER 過程;
(5) 啓用,使用ENABLE 過程;
(6) 禁用,使用DISABLE 過程;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章