【JOB】Oracle JOB全面學習(DBMS_JOB和DBMS_SCHEDULER)

lhrbest發表於2017-07-24

【JOB】Oracle JOB全面學習(DBMS_JOB和DBMS_SCHEDULER)




oracle定時任務(dbms_job)

author:skate

time:2007-09-12

http://publish.it168.com/2006/0311/20060311017002.shtml

今天總結下oracle的任務佇列管理器(job queue ),以後也方便查詢.
 我們要做定時任務時,有兩種辦法

一種是: 作業系統的定時,win的定時任務,unix的crontab
一種是: 資料庫級的定時,她的效率更高,


再有大量的表級操作時,建議用資料庫本身的job queue,這樣方便,效率高;如果用系統級定時,
會增加很多程式設計工作,成本增加了,還很容易出錯,事情越簡單出錯的機率越小.

 

再使用job queue之前,我們還要簡單配置下,oracle定時執行job queue 的後臺程式是SNP,要啟動

snp,首先看系統模式是否支援

sql> alter system enable restricted session;

sql> alter system disenable restricted session;

利用上面的命令更改系統的會話方式為disenable restricted,為snp的啟動建立條件.


再有就是配置job queue的啟動引數,snp的啟動引數位於oracle的初始化檔案中,
job_queue_processes=10   (oracle10gde 預設值)
job_queue_interval=N

第一行定義snp程式的啟動個數為10,正常得女冠一範圍是0-36,根據任務的多少,可以配置
不同的數值.

第二行定義系統每隔幾秒喚醒該程式一次.預設是60,正常範圍是1-3600秒.事實上,該程式執行完

當前任務後,就進入睡眠狀態,睡眠一段時間後,由系統的總控負責將其喚醒。  
如果該檔案中沒有上面兩行,請按照如上配置新增。配置完成後,需要重新啟動資料庫,使其生效

。注意:如果任務要求執行的間隔很短的話,N的配置也要相應地小一點。


檢視job queue的詳細資訊,查詢資料庫字典 user_jobs

eg:
 sql> select job,next_date,next_sec,broken from user_jobs;

 

包含以下子過程: 

Broken()過程。 
change()過程。 
Interval()過程。 
Isubmit()過程。 
Next_Date()過程。 
Remove()過程。 
Run()過程。 
Submit()過程。 
User_Export()過程。 
What()過程。

1、 
Broken()過程更新一個已提交的工作的狀態,典型地是用來把一個已破工作標記為未破工作。 
這個過程有三個引數:job 、broken與next_date。

PROCEDURE Broken (job       IN binary_integer, 
                  Broken    IN boolean, 
                  next_date IN date :=SYSDATE)

job引數是工作號,它在問題中唯一標識工作。 
broken引數指示此工作是否將標記為破——TRUE說明此工作將標記為破,而FLASE說明此工作將標記為未破。 
next_date引數指示在什麼時候此工作將再次執行。此引數預設值為當前日期和時間。

 

2、 
Change()過程用來改變指定工作的設定。 
這個過程有四個引數:job、what 、next_date與interval。

PROCEDURE Change (job        IN binary_integer, 
                  What       IN varchar2, 
                  next_date  IN date, 
                  interval   IN varchar2)

此job引數是一個整數值,它唯一標識此工作。 
What引數是由此工作執行的一塊PL/SQL程式碼塊。 
next_date引數指示何時此工作將被執行。 
interval引數指示一個工作重執行的頻度。

 

3、 
Interval()過程用來顯式地設定重執行一個工作之間的時間間隔數。 
這個過程有兩個引數:job與interval。

PROCEDURE Interval (job      IN binary_integer, 
                    Interval IN varchar2)

job引數標識一個特定的工作。interval引數指示一個工作重執行的頻度。

 

4、 
ISubmit()過程用來用特定的工作號提交一個工作。 
這個過程有五個引數:job、what、next_date、interval與no_parse。

PROCEDURE ISubmit (job       IN binary_ineger, 
                   What      IN varchar2, 
                   next_date IN date, 
                   interval  IN varchar2, 
                   no_parse  IN booean:=FALSE)

這個過程與Submit()過程的唯一區別在於此job引數作為IN型引數傳遞且包括一個 
由開發者提供的工作號。如果提供的工作號已被使用,將產生一個錯誤。


5、 
Next_Date()過程用來顯式地設定一個工作的執行時間。這個過程接收兩個引數:job與next_date。

PROCEDURE Next_Date(job         IN binary_ineger, 
                    next_date   IN date)

job標識一個已存在的工作。next_date引數指示了此工作應被執行的日期與時間。

 

6、 
Remove()過程來刪除一個已計劃執行的工作。這個過程接收一個引數:

PROCEDURE Remove(job IN  binary_ineger);

job引數唯一地標識一個工作。這個引數的值是由為此工作呼叫Submit()過程返回的job引數的值。 
已正在執行的工作不能由呼叫過程式刪除。

 

7、 
Run()過程用來立即執行一個指定的工作。這個過程只接收一個引數:

PROCEDURE Run(job IN binary_ineger) 

job引數標識將被立即執行的工作。

 

8、 
使用Submit()過程,工作被正常地計劃好。 
這個過程有五個引數:job、what、next_date、interval與no_parse。

PROCEDURE Submit ( job       OUT binary_ineger, 
                   What      IN  varchar2, 
                   next_date IN  date, 
                   interval  IN  varchar2, 
                   no_parse  IN  booean:=FALSE)

job引數是由Submit()過程返回的binary_ineger。這個值用來唯一標識一個工作。 
what引數是將被執行的PL/SQL程式碼塊。 
next_date引數指識何時將執行這個工作。 
interval引數何時這個工作將被重執行。 
no_parse引數指示此工作在提交時或執行時是否應進行語法分析——TRUE 
指示此PL/SQL程式碼在它第一次執行時應進行語法分析, 
而FALSE指示本PL/SQL程式碼應立即進行語法分析。

 

9、 
User_Export()過程返回一個命令,此命令用來安排一個存在的工作以便此工作能重新提交。 
此程式有兩個引數:job與my_call。

PROCEDURE User_Export(job        IN binary_ineger, 
                      my_call    IN OUT varchar2)

job引數標識一個安排了的工作。my_call引數包含在它的當前狀態重新提交此工作所需要 
的正文。

 

10、 
What()過程應許在工作執行時重新設定此正在執行的命令。這個過程接收兩個引數:job與what。

PROCEDURE What (job  IN binary_ineger, 
                What IN OUT varchar2)

job引數標識一個存在的工作。what引數指示將被執行的新的PL/SQL程式碼。

 


一個簡單例子: 

建立測試表 
SQL> create table a(a date);

表已建立。

建立一個自定義過程 
SQL> create or replace procedure test as 
  2  begin 
  3  insert into a values(sysdate); 
  4  end; 
  5  /

過程已建立。

建立JOB 
SQL> variable job1 number; 
SQL>  
SQL> begin 
  2  dbms_job.submit(:job1,'test;',sysdate,'sysdate+1/1440');  --每天1440分鐘,即一分鐘執行test過程一次 
  3  end; 
  4  /

PL/SQL 過程已成功完成。

執行JOB 
SQL> begin 
  2  dbms_job.run(:job1); 
  3  end; 
  4  /

PL/SQL 過程已成功完成。

SQL> select to_char(a,'yyyy/mm/dd hh24:mi:ss') 時間 from a;

時間 
------------------- 
2001/01/07 23:51:21 
2001/01/07 23:52:22 
2001/01/07 23:53:24

刪除JOB 
SQL> begin 
  2  dbms_job.remove(:job1); 
  3  end; 
  4  /

PL/SQL 過程已成功完成。

 

下面說下常用的檢視與引數:

任務佇列中關於任務的資料字典檢視


檢視名 描述
DBA_JOBS 本資料庫中定義到任務佇列中的任務
DBA_JOBS_RUNNING 目前正在執行的任務
USER_JOBS 當前使用者擁有的任務


JOB_QUEUE_PROCESSES  >= 1 (如果系統在同一時間會執行很多的job, 或者還有大量需要自動refresh的snapshot, 適當加大)

JOB_QUEUE_INTERVAL : 秒數(預設為60秒), 根據你的job的排程頻度而定, 對於一般的一天執行一次的job, 設為預設值或者幾分鐘都可以. (不要設定過小, 以免影響效能)

JOB_QUEUE_KEEP_CONNECTION (系統預設就可以,我沒發現他的作用)

 

DBA_JOBS 和 USER_JOBS.字典檢視的欄位含義


欄位(列) 型別 描述
JOB NUMBER 任務的唯一標示號
LOG_USER VARCHAR2(30) 提交任務的使用者
PRIV_USER VARCHAR2(30) 賦予任務許可權的使用者
SCHEMA_USER VARCHAR2(30) 對任務作語法分析的使用者模式
LAST_DATE DATE 最後一次成功執行任務的時間
LAST_SEC VARCHAR2(8) 如HH24:MM:SS格式的last_date日期的小時,分鐘和秒
THIS_DATE DATE 正在執行任務的開始時間,如果沒有執行任務則為null
THIS_SEC VARCHAR2(8) 如HH24:MM:SS格式的this_date日期的小時,分鐘和秒
NEXT_DATE DATE 下一次定時執行任務的時間
NEXT_SEC VARCHAR2(8) 如HH24:MM:SS格式的next_date日期的小時,分鐘和秒
TOTAL_TIME NUMBER 該任務執行所需要的總時間,單位為秒
BROKEN VARCHAR2(1) 標誌引數,Y標示任務中斷,以後不會執行
INTERVAL VARCHAR2(200) 用於計算下一執行時間的表示式
FAILURES NUMBER 任務執行連續沒有成功的次數
WHAT VARCHAR2(2000) 執行任務的PL/SQL塊
CURRENT_SESSION_LABEL RAW MLSLABEL 該任務的信任會話符
CLEARANCE_HI RAW MLSLABEL 該任務可信任的最大間隙
CLEARANCE_LO RAW MLSLABEL 該任務可信任的最小間隙
NLS_ENV VARCHAR2(2000) 任務執行的NLS會話設定
MISC_ENV RAW(32) 任務執行的其他一些會話引數


      檢視DBA_JOBS_RUNNING的欄位含義


資料型別 描述
SID NUMBER 目前正在執行任務的會話ID
JOB NUMBER 任務的唯一標示符
FAILURES NUMBER 連續不成功執行的累計次數
LAST_DATE DATE 最後一次成功執行的日期
LAST_SEC VARCHAR2(8) 如HH24:MM:SS格式的last_date日期的小時,分鐘和秒
THIS_DATE DATE 目前正在執行任務的開始日期
THIS_SEC VARCHAR2(8) 如HH24:MM:SS格式的this_date日期的小時,分鐘和秒


 

任務重複執行間隔和間隔設計

 
演算法任務重複執行的時間間隔取決於interval引數中設定的日期表示式。下面就來詳細談談該如何設定interval引數才能準確滿足我們的任務需求。一般來講,對於一個任務的定時執行,有三種定時要求。

    在一個特定的時間間隔後,重複執行該任務。

    在特定的日期和時間執行任務。

    任務成功完成後,下一次執行應該在一個特定的時間間隔之後。

    第一種排程任務需求的日期演算法比較簡單,即'SYSDATE+n',這裡n是一個以天為單位的時間間隔。表6給出了一些這種時間間隔設定的例子。

    表6 一些簡單的interval引數設定例子


描述 Interval引數值
每天執行一次 'SYSDATE + 1'
每小時執行一次 'SYSDATE + 1/24'
每10分鐘執行一次 'SYSDATE + 10/(60*24)'
每30秒執行一次 'SYSDATE + 30/(60*24*60)'
每隔一星期執行一次 'SYSDATE + 7'
不再執行該任務並刪除它 NULL


     表6所示的任務間隔表示式不能保證任務的下一次執行時間在一個特定的日期或者時間,僅僅能夠指定一個任務兩次執行之間的時間間隔。例如,如果一個任務第一次執行是在凌晨12點,interval指定為'SYSDATE + 1',則該任務將被計劃在第二天的凌晨12點執行。但是,如果某使用者在下午4點手工(DBMS_JOB.RUN)執行了該任務,那麼該任務將被重新定時到第二天的下午4點。還有一個可能的原因是如果資料庫關閉或者說任務佇列非常的忙以至於任務不能在計劃的那個時間點準時執行。在這種情況下,任務將試圖儘快執行,也就是說只要資料庫一開啟或者是任務佇列不忙就開始執行,但是這時,執行時間已經從原來的提交時間漂移到了後來真正的執行時間。這種下一次執行時間的不斷“漂移”是採用簡單時間間隔表示式的典型特徵。

    第二種排程任務需求相對於第一種就需要更復雜的時間間隔(interval)表示式,表7是一些要求在特定的時間執行任務的interval設定例子。

    表 7. 定時到特定日期或時間的任務例子


描述 INTERVAL引數值
每天午夜12點 'TRUNC(SYSDATE + 1)'
每天早上8點30分 'TRUNC(SYSDATE + 1) + (8*60+30)/(24*60)'
每星期二中午12點 'NEXT_DAY(TRUNC(SYSDATE ), ''TUESDAY'' ) + 12/24'
每個月第一天的午夜12點 'TRUNC(LAST_DAY(SYSDATE ) + 1)'
每個季度最後一天的晚上11點 'TRUNC(ADD_MONTHS(SYSDATE + 2/24, 3 ), 'Q' ) -1/24'
每星期六和日早上6點10分 'TRUNC(LEAST(NEXT_DAY(SYSDATE, ''SATURDAY"), NEXT_DAY(SYSDATE, "SUNDAY"))) + (6×60+10)/(24×60)'


      第三種排程任務需求無論透過怎樣設定interval日期表示式也不能滿足要求。這時因為一個任務的下一次執行時間在任務開始時才計算,而在此時是不知道任務在何時結束的。遇到這種情況怎麼辦呢?當然辦法肯定是有的,我們可以透過為任務佇列寫過程的辦法來實現。這裡我只是簡單介紹以下,可以在前一個任務佇列執行的過程中,取得任務完成的系統時間,然後加上指定的時間間隔,拿這個時間來控制下一個要執行的任務。這裡有一個前提條件,就是目前執行的任務本身必須要嚴格遵守自己的時間計劃。


 

 

Oracle dbms_job package 用法小結



一、設定初始化引數 job_queue_processes 
      job_queue_processes=4   
      job_queue_interval=10   
sql> alter system set job_queue_processes=n;(n>0) 
job_queue_processes最大值為1000  

檢視job queue 後臺程式 
sql>select name,description from v$bgprocess;


二、dbms_job package 用法介紹 
包含以下子過程:    
Broken()過程。 
change()過程。 
Interval()過程。 
Isubmit()過程。 
Next_Date()過程。 
Remove()過程。 
Run()過程。 
Submit()過程。 
User_Export()過程。 
What()過程。  

1、Broken()過程更新一個已提交的工作的狀態,典型地是用來把一個已破工作標記為未破工作 
這個過程有三個引數:job 、broken與next_date。  

PROCEDURE Broken ( job  IN binary_integer, 
       Broken  IN boolean, 
       next_date IN date :=SYSDATE)  

job引數是工作號,它在問題中唯一標識工作。 
broken引數指示此工作是否將標記為破——TRUE說明此工作將標記為破,而FLASE說明此工作將標記為未破。 
next_date引數指示在什麼時候此工作將再次執行。此引數預設值為當前日期和時間。

job如果由於某種原因未能成功之行,oracle將重試16次後,還未能成功執行,將被標記為broken重新啟動狀態為broken的job,有如下兩種方式;

a、利用dbms_job.run()立即執行該job 
sql>begin 
sql>dbms_job.run(:jobno) 該jobno為submit過程提交時返回的job number 
sql>end; 
sql>/

b、利用dbms_job.broken()重新將broken標記為false 
sql>begin 
sql>dbms_job.broken (:job,false,next_date) 
sql>end; 
sql>/

2、Change()過程用來改變指定工作的設定。 
這個過程有四個引數:job、what 、next_date與interval。   
PROCEDURE Change (  job IN binary_integer, 
             What IN varchar2, 
             next_date IN date, 
             interval  IN varchar2)  

此job引數是一個整數值,它唯一標識此工作。 
What引數是由此工作執行的一塊PL/SQL程式碼塊。 
next_date引數指示何時此工作將被執行。 
interval引數指示一個工作重執行的頻度。 


3、Interval()過程用來顯式地設定重執行一個工作之間的時間間隔數。這個過程有兩個引數:job與interval   
PROCEDURE Interval ( job IN binary_integer, 
             Interval IN varchar2)  

job引數標識一個特定的工作。interval引數指示一個工作重執行的頻度。 


4、ISubmit()過程用來用特定的工作號提交一個工作。這個過程有五個引數:job、what、next_date、interval與no_parse

PROCEDURE ISubmit ( job IN binary_ineger, 
             What IN varchar2, 
             next_date IN date, 
             interval  IN varchar2, 
             no_parse IN booean:=FALSE)  

這個過程與Submit()過程的唯一區別在於此job引數作為IN型引數傳遞且包括一個由開發者提供的工作號。如果提供的工作號已被使用,將產生一個錯誤。  

 

5、Next_Date()過程用來顯式地設定一個工作的執行時間。這個過程接收兩個引數:job與next_date  

PROCEDURE Next_Date( job IN binary_ineger, 
              next_date IN date) 
job標識一個已存在的工作。next_date引數指示了此工作應被執行的日期與時間。 


6、Remove()過程來刪除一個已計劃執行的工作。這個過程接收一個引數:   
PROCEDURE Remove(job  IN binary_ineger);   
job引數唯一地標識一個工作。這個引數的值是由為此工作呼叫Submit()過程返回的job引數的值。已正在執行的工作不能由呼叫過程式刪除。  

 

7、Run()過程用來立即執行一個指定的工作。這個過程只接收一個引數: 
PROCEDURE Run(job IN binary_ineger)    
job引數標識將被立即執行的工作。  

 

8、使用Submit()過程,工作被正常地計劃好 
這個過程有五個引數:job、what、next_date、interval與no_parse。  

PROCEDURE Submit (   job OUT binary_ineger, 
             What IN varchar2, 
             next_date IN date, 
             interval  IN varchar2, 
             no_parse IN booean:=FALSE)   
job引數是由Submit()過程返回的binary_ineger。這個值用來唯一標識一個工作。 
what引數是將被執行的PL/SQL程式碼塊。 
next_date引數指識何時將執行這個工作。 
interval引數何時這個工作將被重執行。 
no_parse引數指示此工作在提交時或執行時是否應進行語法分析——TRUE指示此PL/SQL程式碼在它第一次執行時應進行語法分析,而FALSE指示本PL/SQL程式碼應立即進行語法分析。 

 

示例:

begin
  sys.dbms_job.submit(job => :job,
                      what => test_sql;',
                      next_date => trunc(sysdate)+23/24,
                      interval => 'trunc(next_day(sysdate,''星期五''))+23/24');
  commit;
end;

     其中:job是系統自動產生編號,test_sql是一個過程,next_date設定下次執行時間,這裡是今天晚上23:00,interval設定時間間隔,多久執行一次,這裡是每週的星期五晚上23:00,函式next_day返回日期中包含指定字元的日期,trunc 函式去掉日期裡的時間,也就是得到的是某天的00:00,時間是以天為單位的所以要得到某某點某某分,就需要分數:

1/24      一小時;
1/1440    一分;
1/3600    一秒; 

 

 

9、User_Export()過程返回一個命令,此命令用來安排一個存在的工作以便此工作能重新提交此程式有兩個引數:job與my_call。   
PROCEDURE User_Export( job IN binary_ineger,
                       my_call IN OUT varchar2)   
job引數標識一個安排了的工作。my_call引數包含在它的當前狀態重新提交此工作所需要的正文。 

 

10、What()過程應許在工作執行時重新設定此正在執行的命令。這個過程接收兩個引數:job與what   
PROCEDURE What ( job  IN binary_ineger,
              What IN OUT varchar2) 
job引數標識一個存在的工作。what引數指示將被執行的新的PL/SQL程式碼。 


三、檢視相關job資訊 
1、相關檢視 
dba_jobs 
all_jobs 
user_jobs 
dba_jobs_running 包含正在執行job相關資訊  

2、檢視相關資訊   
SQL>select JOB, NEXT_DATE, NEXT_SEC, FAILURES, BROKEN FROM DBA_JOBS;  

正在執行的JOB相關資訊   
select SID, r.JOB, LOG_USER, r.THIS_DATE, r.THIS_SEC FROM DBA_JOBS_RUNNING r, DBA_JOBS j where r.JOB = j.JOB; 
  
JOB QUEUE LOCK相關資訊   
select SID, TYPE, ID1, ID2 FROM V$LOCK where TYPE = ’JQ’;

 

四、簡單例子 
一個簡單例子:    
建立測試表 
SQL> create table TEST(tm date);   
表已建立。   
建立一個自定義過程 
SQL> create or replace procedure MYPROC as 
2 begin 
3 insert into TEST values(sysdate); 
4 end; 
5 /   
過程已建立。   
建立JOB 
SQL> variable job1 number; 
SQL> 
SQL> begin 
2 dbms_job.submit(:job1,'MYPROC;',sysdate,'sysdate+1/1440');  --每天1440分鐘,即一分鐘執行test過程一次 
3 end; 
4 /   
PL/SQL 過程已成功完成。 
 
檢視Job號
SQL> print job1;

      JOB1
----------
        21

執行JOB 
SQL> begin 
2 dbms_job.run(:job1); 
3 end; 
4 /   
PL/SQL 過程已成功完成。 

驗證 

SQL> select to_char(tm,'yyyy/mm/dd hh24:mi:ss') 時間 from TEST;

時間
-------------------
2009/08/24 17:21:02
2009/08/24 17:24:07
2009/08/24 17:25:09
刪除JOB

SQL> begin 
2 dbms_job.remove(:job1); 
3 end; 
4 /   
PL/SQL 過程已成功完成。

 

五. 實際應用示例:定時analyzed所有表,因為必須對錶分析以後,num_rows 才會有值 

1.建立儲存過程:

CREATE OR REPLACE PROCEDURE USER."ANALYZEDB" 
IS
   CURSOR get_ownertable
   IS
      SELECT table_name
        FROM user_tables;

   ownertable   get_ownertable%ROWTYPE;
BEGIN
   OPEN get_ownertable;

   LOOP
      FETCH get_ownertable
       INTO ownertable;

      EXIT WHEN get_ownertable%NOTFOUND;

      EXECUTE IMMEDIATE    'analyze table '
                        || ownertable.table_name
                        || ' compute statistics for table for all indexes for all indexed columns ';
   END LOOP;
EXCEPTION
   WHEN OTHERS
   THEN
      RAISE;
END;
/

 

2. 建立JOB.

BEGIN 
  SYS.DBMS_JOB.REMOVE(3);
COMMIT;
END;
/

DECLARE
  X NUMBER;
BEGIN
  SYS.DBMS_JOB.SUBMIT
  ( job       => X 
   ,what      => 'ANALYZEDB;'
   ,next_date => to_date('26-08-2009 06:00:00','dd/mm/yyyy hh24:mi:ss')
   ,interval  => 'trunc(sysdate + 7) + 6/24'
   ,no_parse  => FALSE
  );
  SYS.DBMS_OUTPUT.PUT_LINE('Job Number is: ' || to_char(x));
COMMIT;
END;
/

0   0




三思筆記系列文章之

全面學習 ORACLE 資料庫 SCHEDULER 特性

2009-08

所謂出於 job 而勝於 job,說的就是 Oracle 10g 後的新特性 Scheduler 啦。在 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 過程呼叫還是比較簡單的,例如:

JSSWEB> BEGIN

2                  DBMS_SCHEDULER.CREATE_JOB (

3                  job_name =>   'INSERT_TEST_TBL',

4                  job_type  =>   'STORED_PROCEDURE',

5                  job_action      =>   'P_INSERTINTOTEST',

6                  start_date =>   sysdate,

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

8                  END;

9                  /

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 將自動被修改為 COMPLETEDENABLED 被置為 FALSE。如果該引數設定為空的話,表示該任務永不過期,將一直按照

REPEAT_INTERVAL 引數設定的週期重複執行,直到達到設定的 MAX_RUNS MAX_FAILURES 值。

?  JOB_CLASS:指定任務關聯的 CLASS,預設值為 DEFAULT_JOB_CLASS。關於 JOB CLASS 的資訊就關注本系列的後續文章。

?  ENABLED:指定任務是否啟用,預設值為 FALSEFALSE 狀態表示該任務並不會被執行,除非被使用者手動呼叫,或者使用者將該任務的狀態修改為 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 也可以),例如:

JSSWEB>      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 引數嗎,當不顯式指定時,該引數的預設值為 falseJOB 自然不會執行了。如果遇到這類情形,如何修改呢?請繼續關注下一節。

1.2 管理 Jobs

1.2.1 啟用 Jobs

前面建立 JOB 時,由於未顯式的指定 ENABLED 引數,因此即使指定了 START_DATE,不過預設情況下 JOB

不會自動執行。對於這種情況,DBMS_SCHEDULER 包中提供了一個過程 ENABLE,可以用來修改 JOB 的啟用狀態,呼叫方式非常簡單,例如:

JSSWEB> exec dbms_scheduler.enable('INSERT_TEST_TBL'); PL/SQL procedure successfully completed.

1.2.2 禁用 Jobs

DBMS_SCHEDULER.ENABLE 僅用來將 JOB(其實不僅僅對 JOB 有效,對於 CHAINPROGRAM 等也有

)的啟用狀態置為 TRUE。如果想將其啟用狀態置為 FALSE?簡單,還有一個與該功能對應的過程:

DBMS_SCHEDULER.DISABLE,例如:

JSSWEB> 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,可以用來修改任務的屬性值。

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

JSSWEB> exec dbms_scheduler.set_attribute('INSERT_TEST_TBL','JOB_ACTION','P_INSERTINTOTEST');

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

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

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

JSSWEB> 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 子程式;  EXECUTEABLEORACLE 資料庫之外的應用,比如作業系統命令等等。

建立 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

COMMENTS                     VARCHAR2            IN     Y

如上所示,前三項為必選引數,各引數實際代表的意義如下:

? PROGRAM_NAME:指定一個 program 名稱;

? PROGRAM_TYPEProgram 的型別,如前文中所述,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

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.

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 建立和管理 Schedules

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_INTERVALCOMMENTSEND_DATESTART_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=WEEKLY; 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 兩個關鍵字,其實除此之外,還有如 BYMONTHBYWEEKNOBYYEARDAYBYDATE 等等引數,可以用來進行更精確的定義,比如透過 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';

設定任務在每天的下午 456 點時執行:

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', DBMS_SCHEDULER.JOB_ALL_EVENTS)

3           END;

4           /

PL/SQL procedure successfully completed.

'raise_events',

上述示例中指定的 raise_events 屬性的屬性值 DBMS_SCHEDULER.JOB_ALL_EVENTS,就是丟擲 Events 的觸發條件。

觸發 Events 的有下列的型別,分別代表不同的操作:

?  job_startedJOB 啟動;

?  job_succeededJOB 成功結束;

?  job_failedJOB 執行失敗;

?  job_brokenJOB 被置為 BROKEN 狀態;

?  job_completedJOB 達到最大執行次數,或者執行的結束日期;

?  job_stoppedJOB STOP_JOB 過程置為停止執行的狀態;

?  job_sch_lim_reachedJob schedule 達到限定值;

?  job_disabledJOB 被置於 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_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 => '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:DPrograms:ABCD 以及執行的邏輯關係就構成了一個最簡單的 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:指定日誌記錄的級別,有下列三種級別:

?  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 引數為必選參外,其它均為可選引數,例如:

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 過程;這些過程的呼叫方式也都非常簡單,這裡就不著重演示了,感興趣的朋友不妨自行嘗試。






About Me

...............................................................................................................................

● 本文整理自網路

● 本文在itpub(http://blog.itpub.net/26736162)、部落格園(http://www.cnblogs.com/lhrbest)和個人微信公眾號(xiaomaimiaolhr)上有同步更新

● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/

● 本文部落格園地址:http://www.cnblogs.com/lhrbest

● 本文pdf版及小麥苗雲盤地址:http://blog.itpub.net/26736162/viewspace-1624453/

● 資料庫筆試面試題庫及解答:http://blog.itpub.net/26736162/viewspace-2134706/

● QQ群:230161599     微信群:私聊

● 聯絡我請加QQ好友(646634621),註明新增緣由

● 於 2017-07-01 09:00 ~ 2017-07-31 22:00 在魔都完成

● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

...............................................................................................................................

拿起手機使用微信客戶端掃描下邊的左邊圖片來關注小麥苗的微信公眾號:xiaomaimiaolhr,掃描右邊的二維碼加入小麥苗的QQ群,學習最實用的資料庫技術。

【JOB】Oracle JOB全面學習(DBMS_JOB和DBMS_SCHEDULER)
DBA筆試面試講解
歡迎與我聯絡

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2142477/,如需轉載,請註明出處,否則將追究法律責任。

相關文章