Oracle數據庫——Scheduler Job


日常的運維工作中,我們經常使用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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM