Oracle資料庫——Scheduler Job

張衝andy發表於2016-12-10

日常的運維工作中,我們經常使用Linux Server的anacron服務來使得伺服器執行一下計劃之內的任務,可以按照特定的時間間隔,重複的執行相關的命令或者相關的指令碼,來完成預期的目標,能夠節省相關的人力,使得運維變得更加容易。

對於Oracle資料庫來說,當然也提供了相關的功能來實現定時的,重複的完成PL/SQL Block,Shell Scripts(其實是External Executables,在這裡簡單用shell指令碼代替),以及Oracle本身已經編寫好的Storage Procedure或者使用者自定義Function。

在早期的Oracle Database中,Job就是實現了該功能的主力軍,透過DBMS_JOB包就可以完成對Job的定義,修改,刪除。從Oracle 10g的版本開始,Oracle提供了更強大的功能--Scheduler Job,隨著功能的強大,那麼定義的方式也會變的相對更加的複雜,下面我們就開始對相關的知識進行一下探討:


一、Scheduler Job Concepts

這裡對Scheduler Job暫且簡稱為Job,如果後面有對之前版本使用的Job的對比,我會把其稱之為“舊版的Job”。

對於Job的概念,為了嚴謹,我會從官方手冊上進行摘錄和翻譯。

詳情請參照官方手冊“Administrator’s Guide”文件,28章節“Oracle scheduler Concepts”。

The Scheduler provides sophisticated, flexible enterprise scheduling functionality, which you can use to:

Run database program units


1.You can run program units, that is, PL/SQL anonymous blocks, PL/SQL stored procedures, and Java stored procedures on the local database or on one or more remote Oracle databases.


2.Run external executables, (executables that are external to the database)


You can run external executables, such as applications, shell scripts, and batch files, on the local system or on one or more remote systems. Remote systems do not require an Oracle Database installation; they require only a Scheduler agent. Scheduler agents are available for all platforms supported by Oracle Database and some additional platforms.


這裡詳細說明了,Oracle的Scheduler不僅僅可以提供自動執行本地Oracle程式單元(包括PL/SQL匿名塊,PL/SQL儲存過程,JAVA儲存過程),還可以執行Oracle資料庫之外的本地或者遠端伺服器上的可以執行程式,例如應用,shell指令碼或者批處理檔案。甚至在遠端伺服器上不需要安裝Oracle資料庫軟體。遠端主機僅僅需要Oracle Scheduler的代理軟體,Oracle Scheduler代理軟體能部署在任何支援Oracle軟體安裝的平臺上,還有一些附加的平臺之上。


對於Scheduler的定義方式,Oracle提供了以下三種方式:

1.基於時間(Time-based scheduling)的日程

這種方式就是我們最常見到的,功能類似於anacron的定義方式,它可以透過指定一段時間,甚至永久的日程,來重複的在指定的時間點完成某項特定的任務。

2.基於事件(Events-based scheduling)的日程

你可以在發生系統事件或者業務事件的時候,對它們進行回應來觸發相關的計劃任務,在我看來,就像觸發器,滿足特定條件,或者發生指定事件,就可以觸發相關的任務。這也是透過anacron沒有辦法完成的一種強大功能。

3.獨立(Dependency scheduling)日程

這一類的日程是可以透過上一件日程的完成來觸發的,上一次的Job完成之後,則會觸發下一個Job,這樣就形成了一條“作業鏈”(Job Chain),需要和基於事件的日程區分的是,系統事件和業務事件並不是一丁是之前的Job。


二、Scheduler Data Dictionary Views


既然需要Job來替我們完成計劃任務,我們就需要對其進行監控以防止中斷的程式,無效的程式以及一些始料未及的情況,下面就來介紹一下相關的資料字典表。


View Description

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

*_SCHEDULER_CHAIN_RULES

These views show all rules for all chains.

*_SCHEDULER_CHAIN_STEPS

These views show all steps for all chains.

*_SCHEDULER_CHAINS

These views show all chains.

*_SCHEDULER_CREDENTIALS

These views show all credentials.

*_SCHEDULER_DB_DESTS

These views show all database destinations.

*_SCHEDULER_DESTS

These views show all destinations, both database and external.

*_SCHEDULER_EXTERNAL_DESTS

These views show all external destinations.

*_SCHEDULER_FILE_WATCHERS

These views show all file watchers.

*_SCHEDULER_GLOBAL_ATTRIBUTE

These views show the current values of Scheduler attributes.

*_SCHEDULER_GROUP_MEMBERS

These views show all group members in all groups.

*_SCHEDULER_GROUPS

These views show all groups.

*_SCHEDULER_JOB_ARGS

These views show all set argument values for all jobs.

*_SCHEDULER_JOB_CLASSES

These views show all job classes.

*_SCHEDULER_JOB_DESTS

These views show the state of both local jobs and jobs at remote destinations, including child jobs of multiple-destination jobs. You obtain job destination IDs (job_dest_id) from these views.

*_SCHEDULER_JOB_LOG

These views show job runs and state changes, depending on the logging level set.

*_SCHEDULER_JOB_ROLES

These views show all jobs by Oracle Data Guard database role.

*_SCHEDULER_JOB_RUN_DETAILS

These views show all completed (failed or successful) job runs.

*_SCHEDULER_JOBS

These views show all jobs, enabled as well as disabled.

*_SCHEDULER_NOTIFICATIONS

These views show all job state e-mail notifications.

*_SCHEDULER_PROGRAM_ARGS

These views show all arguments defined for all programs as well as the default values if they exist.

*_SCHEDULER_PROGRAMS

These views show all programs.

*_SCHEDULER_RUNNING_CHAINS

These views show all chains that are running.

*_SCHEDULER_RUNNING_JOBS

These views show state information on all jobs that are currently being run.

*_SCHEDULER_SCHEDULES

These views show all schedules.

*_SCHEDULER_WINDOW_DETAILS

These views show all completed window runs.

*_SCHEDULER_WINDOW_GROUPS

These views show all window groups.

*_SCHEDULER_WINDOW_LOG

These views show all state changes made to windows.

*_SCHEDULER_WINDOWS

These views show all windows.

*_SCHEDULER_WINGROUP_MEMBERS

These views show the members of all window groups, one row for each group member.

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


在這裡我們經常使用的檢視有

*_SCHEDULER_RUNNING_JOBS:描述正在執行的Job的相關資訊

*_SCHEDULER_JOB_RUN_DETAILS:描述已經完成的Job是否成功,記錄相關日誌的檢視,這裡記錄著所有已經執行完畢的日程

*_SCHEDULER_SCHEDULES:描述當前資料庫所有已知的日程。

*_SCHEDULER_PROGRAMS:描述當前資料庫已經定義完畢的程式。

*_SCHEDULER_JOBS:描述當前資料庫已經定義完畢的作業。

對於日程,程式,作業的概念會在稍後介紹,請耐心往下看。


三、Schedule、Program、Job Concepts


對於它們的概念,可以從文字的字面意思上進行理解。

首先從Job這個最核心的部分開始理解吧,Job意為作業,也就是計劃任務的本質,之前說過之前版本的Oracle Database也是透過Job來定義計劃任務的,只不過這裡的Job和舊版本的Job不太一樣,他支援更多的功能。

Job作為整個Scheduler Job的核心,他是用來描述如何完成一個作業的。

它將會定義如下內容:

1.When

何時完成該項作業,指定時間,這也是計劃任務中“計劃”的含義,指定確定的時間完成確定的操作或者事件。當然,該項也可以不定義,透過在Schedule(日程)中指定時間和時間間隔更加合理,之後會有相應的解釋。

2.Where(Destination)

究竟Job在哪裡完成,之前在Scheduler Concepts我就介紹過,Job也可以在遠端的主機上完成,當然需要進行Agent的部署,如果不對該項進行定義,那麼該任務預設在本地完成。

3.How

這個很重要,因為你總要知道你在特定的時間點需要做什麼事情吧?在之前的Scheduler Concepts我也提到,Scheduler Job可以定義多種任務實現方式。

1)PL/SQL anonymous  Block

2)Shell Scripts

3)External Executables

我們可以在Job中定義這些Action(動作),當然也可以在Program中定義,我們稍後會講解program。



現在我們來介紹一下schedule,日程,也就是用來定義今天或者截下來的幾天,甚至今後的時間需要在某個特定的時間完成什麼樣的事情。

它僅僅用來定義時間和時間間隔,這樣的說法比較抽象,下面用一個例子來說明:

我現在對Oracle非常感興趣,想要對Oracle技術進行學習,那麼我每天看Oracle的時間為固定1小時,不會被其他事情打擾,且必須要在17:00-20:00之間抽出一個小時,因為還有別的安排。那麼我就會抽出最合理的一小時進行定義。

例如,我要在每週一到週五的19:00-20:00完成Oracle的學習,這是學習本身的時間,不能由我們定義,所以這裡19-20點既不是指的時間也不是指的時間間隔,而是完成作業本身所需要的固定時間。

而19:00則是我所說的時間,也就是作業開始的時間,也就是說我會定義19點為作業的start_time。

那時間間隔是什麼呢?我之前說了那就是每個週一到週五中的每一天,到了週五完成Job之後又需要72小時的等待才能進行下一次的任務。

那這裡的每週一到週五的17點,就是我的Scheduler設定的時間間隔和開始時間。

那如何建立一個schedule呢?使用DBMS_SCHEDULER包就可以完成了。建立好的Job如果沒有定義時間,那麼就可以指定一個schedule,使用它定義的時間來完成Job。簡單的來說,就是Job呼叫了Schedule來獲取它要進行Job的時間並且參照該時間執行。


介紹完了schedule,那麼program大家應該也就可以聯想到了,也就是定義做什麼事情,當Job沒有定義做Action的時候則可以呼叫program中定義的action進行Job。


好了,說了那麼多,究竟Oracle為什麼要在新版本的Job中新增這麼多的定義?最簡單的例子,如果我想在同一時間做不同的很多事情,我就需要定義很多Job,那麼這個Job需要定義很多次重複的時間。

如果我定義了schedule,我是否只需要將Job1~Jobn都呼叫同一個Schedule就好了呢?這樣做事情的時間就統一了。

對於program就不用多說了吧?再簡單不過的就是在不同的時間做同一間事情了,難不成你要把幾百行的shell指令碼定義好多遍?敲死你你也寫不完。


四、Example


那麼我現在想要在每天的13點對資料庫進行一個全庫的備份,下面就來演示一下如何去做。

首先我們需要去定義一下做什麼,我們有一個備份指令碼,叫做full_backup01.sh,它位於/home/oracle下。我們來檢視一下它的內容。

$ cat /home/oracle/full_backup01.sh

#!/bin/bash

export ORACLE_SID=ora11g

export ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1

#由於Linux執行指令碼的時候會開啟新的shell,不繼承parent shell的環境變數,所以需要定義

export DATE=`date +%Y-%m-%d_%H:%M:%S`

export LOG=full_backup_$DATE.log

export DIR=/home/oracle/backup_log


if  [  ! -d “$DIR”  ]; then

mkdir -p $DIR

echo ‘Create Directory $DIR successful …’ > $DIR/$LOG

else 

$ORACLE_HOME/bin/rman  target /  << EOF

run {

spool to /home/oracle/configuration.log;

show all;

spool off;

configure retention policy to redundancy 1;

configure backup optimization on;

configure controlfile autobackup on;

spool to “$DIR/$LOG”

allocate channel c1 type disk;

allocate channel c2 type disk;

backup incremental level 0 database plus archivelog;

release channel c1;

release channel c2;

spool off;

exit;

    }

EOF

fi

這是一個非常簡單的備份指令碼,進行了一次0級增量備份,並且備份了archivelog,該指令碼應該能夠被Oracle使用者執行。

$ chown oracle:oinstall /home/oracle/full_backup_01.sh

$ chmod u+x /home/oracle/full_backup_01.sh


首先我們來定義一個program,這個program描述了我們做什麼,也就是執行該shell指令碼

SQL>  BEGIN

2 DBMS_SCHEDULER.CREATE_PROGRAM(

3 program_name => ‘my_program’,

4 program_type => ‘executable’,

5 program_action => ‘/home/oracle/full_backup_01.sh’,

6 enabled => true);

7 END;

8 /


PL/SQL procedure successfully completed.

這裡有多個引數可以定義,但是最主要的是以上四個,有了它們,這個program就可以正常執行,首先是program的名字,既然作為資料庫物件,就需要一個名字,這裡不再贅述。

program type。這裡有三種選項:

1.PLSQL_BlOCK 

2.EXECUTABLE

3.STORED_PROCEDURE

也就對應著我之前寫的三種情況,大家如果忘記了,請自行翻閱前面的內容。

program_type則對應著如何執行,對於shell指令碼,執行絕對路徑即可,對於其他兩種,參照PLSQL語法進行寫入即可。

enabled,是否開啟該program,只有enabled的program才可以被Job呼叫,如果設定的false,想要手動啟用的時候需要使用過程dbms_scheduler.enable()。

SQL> exec  DBMS_SCHEDULER.ENABLE(‘MY_PROGRAM’)

PL/SQL procedure successfully completed.

這一步對於Job也是一樣的,不再贅述。



好,完成了“做什麼”,下面我們來定義一下何時去做。

也就是說我們現在要定義一個schedule,對於schedule的定義相對難一些,因為要考慮如何寫時間間隔。

我們下面來定義一下,每天的下午3點執行備份指令碼:

SQL> BEGIN

2 DBMS_SCHEDULER.CREATE_SCHEDULE(

3 schedule_name => ‘my_schedule’,

4 start_date => systimestamp,

5 end_date => systimestamp + interval ’30’ day,

6 repeat_interval => ‘FREQ=DAILY,BYHOUR=15’,

7 comments => ‘my test backup schedule’);

8 END;

9 /

PL/SQL procedure successful completed.

這裡就有一些東西要交代了,每每涉及時間的時候,大家可能會很頭疼,因為不清楚,這裡似乎有三個引數是關於時間的,究竟該如何設定呢。 

首先來講一下start_date引數把。

start_date

This attribute specifies the first date and time on which this schedule becomes valid. For a repeating schedule, the value for start_date is a reference date. In this case, the start of the schedule is not the start_date; it depends on the repeat interval specified. start_date is used to determine the first instance of the schedule.

If start_date is specified in the past and no value for repeat_interval is specified, the schedule is invalid. For a repeating job or window, start_date can be derived from the repeat_interval if it is not specified.

If start_date is null, then the date that the job or window is enabled is used. start_date and repeat_interval cannot both be null.

官方文件對這個引數進行了合理的描述,這個引數指定了這個日程開始有效的時間和日期,對於一個可重複的日程,start_date是一個參考日期。

在這個例子當中,這個schedule的開始日期取決於repeat_interval的值,而不是start_date的值。

如果start_date在之前指定了,但是repeat  interval沒有指定,那麼這個計劃是無效的,對於一個重複執行的job,start_date如果沒有被設定則可以由repeat interval來決定。

如果start_date是null值,那麼Job開始的時間就是Job被enable的時間,所以說,start_date和repeat_interval不能是null值。

也就是說這個Job將會在指定時間以後的第一次符合repeat interval時間間隔的時間運作。


所以如果建立的語句寫成以下的形式:

SQL> BEGIN

2 DBMS_SCHEDULER.CREATE_SCHEDULE(

3 schedule_name => ‘my_schedule’,

4 repeat_interval => ‘FREQ=DAILY,BYHOUR=15’,

5 comments => ‘my test backup schedule’);

6 END;

7 /

PL/SQL procedure successfully completed.

則Job在呼叫該schedule的時候立馬生效,而且永遠都將不過期,而何時過期是由end_date來決定的,所以第一個例子的計劃任務將會在30天以內有效。

關於repeat_interval引數就要好好的解釋一下了:

這個引數有很多的字句,這裡我去官方文件進行摘取子句的內容,大家大概瞭解一下其中的寫法,有一個初步的瞭解。

The following examples illustrate simple repeat intervals. For simplicity, it is assumed that there is no contribution to the evaluation results by the start date.


Run every Friday. (All three examples are equivalent.)


FREQ=DAILY; BYDAY=FRI;        每個週五都執行一遍(下面兩條一樣)

FREQ=WEEKLY; BYDAY=FRI;

FREQ=YEARLY; BYDAY=FRI;

Run every other Friday.   


FREQ=WEEKLY; INTERVAL=2; BYDAY=FRI;(每兩個週五執行一次)

Run on the last day of every month.


FREQ=MONTHLY; BYMONTHDAY=-1;(每個月的上一天搞一下!)

Run on the next to last day of every month.


FREQ=MONTHLY; BYMONTHDAY=-2;(每個月的前兩天搞一下!)

Run on March 10th. (Both examples are equivalent)


FREQ=YEARLY; BYMONTH=MAR; BYMONTHDAY=10;(每年的三月十號執行)

FREQ=YEARLY; BYDATE=0310;

Run every 10 days.


FREQ=DAILY; INTERVAL=10;

Run daily at 4, 5, and 6PM.


FREQ=DAILY; BYHOUR=16,17,18;

Run on the 15th day of every other month.


FREQ=MONTHLY; INTERVAL=2; BYMONTHDAY=15;

Run on the 29th day of every month.


FREQ=MONTHLY; BYMONTHDAY=29;

Run on the second Wednesday of each month.


FREQ=MONTHLY; BYDAY=2WED;

Run on the last Friday of the year.


FREQ=YEARLY; BYDAY=-1FRI;

Run every 50 hours.


FREQ=HOURLY; INTERVAL=50;

Run on the last day of every other month.


FREQ=MONTHLY; INTERVAL=2; BYMONTHDAY=-1;

Run hourly for the first three days of every month.


FREQ=HOURLY; BYMONTHDAY=1,2,3;

官方文件給了好多好多例子,這些例子確實看起來都有點厲害!真的有那麼難寫麼?其實不是,FREQ代表的是頻率,是每年,還是每個月,還是每天。

BYDAY,BYMONTH,BYMONTHDAY就代表著,哪一天,哪一個月,這個月的第幾天。

而INTERVAL=n,就代表著每幾個這樣的間隔就執行一次。舉個例子:

repeat_interval => ‘FREQ=DAILY;BYHOUR=15,16;INTERVAL=2’

那麼頻率就是每天,interval=2,就代表每兩天,每兩天的15點和16點執行一下Job。如果前面是MONTHLY,那麼就是每兩個月了。

不難理解吧?如果還有其他寫法,在官方文件上都會有介紹。YEARLY這種表示時間間隔的詞我就不在這裡進行贅述了,大家可以參照官方文件的PL/SQL Packages and Types References,裡面的DBMS_SCHEDULER文件閱讀一下。


最後的核心內容則是建立一個Job了,如果執行的時間和執行的程式都在Job裡進行定義,那麼引數和之前的program還有schedule所定義的一樣。下面我來建立一個呼叫之前建立的Schedule和Program的一個Job。

SQL> BEGIN

2 DBMS_SCHEDULER.CREATE_JOB(

3 job_name => ‘my_job’,

4 program_name => ‘my_program’,

5 schedule_name => ‘my_schedule’,

6 enabled => true);

7 END;

8 /

PL/SQL procedure successfully completed.

這裡有個引數叫做destination_name和auto_drop,我並沒有寫入,第一個引數代表可以在遠端資料庫上或者遠端主機執行,這個需要部署agent,之前提到過。

而auto_drop則代表,在這個Job在超過了自己定義的或者schedule裡定義的end_date之後,會自動被drop掉,而不是被置為disable狀態。


到此為止,我們建立和配置一個完整的Job就已經結束了。如果要對這些Job進行監控,很簡單,如下檢視和sql可以做到。

SQL> select schedule_name,start_date,repeat_interval,end_date 

2        from dba_scheduler_schedules

3        where lower(schedule_name) = ‘my_schedule’ ;

同理查詢dba_scheduler_programs和dba_scheduler_jobs來檢視program和job的相關資訊。


如果想要看Job的執行後狀態,可以使用以下SQL。

SQL> select log_id,log_date,status,additional_info 

2        from user_scheduler_job_run_details 

3        where lower(job_name)=‘my_job’;


轉:http://blog.itpub.net/31401355/viewspace-2129311/

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

相關文章