Oracle job有定時執行的功能,可以在指定的時間點或每天的某個時間點自行執行任務。
一、查詢系統中的job,可以查詢視圖
--相關視圖
select * from dba_jobs;
select * from all_jobs;
select * fromuser_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_LABELRAW MLSLABEL 該任務的信任Oracle會話符
CLEARANCE_HI RAW MLSLABEL 該任務可信任的Oracle最大間隙
CLEARANCE_LO RAW MLSLABEL 該任務可信任的Oracle最小間隙
NLS_ENV VARCHAR2(2000) 任務運作的NLS會話設定
MISC_ENV RAW(32) 任務運作的其他一些會話參數
*/
-- 正在運作job
select * fromdba_jobs_running;
其中最重要的字段就是job這個值就是我們操作job的id号,what 操作存儲過程的名稱,next_date 執行的時間,interval執行間隔
二、執行間隔interval運作頻率
描述 INTERVAL參數值
每天午夜12點 TRUNC(SYSDATE + 1)
每天早上8點30分 TRUNC(SYSDATE + 1) +(860+30)/(2460)
每星期二中午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 => sysdate+ 1/(24 60 60)
如果改成sysdate + 10/(24 60 60)就是10秒鐘執行次
每分鐘執行
Interval =>TRUNC(sysdate,'mi') + 1/ (24*60)
如果改成TRUNC(sysdate,'mi')+ 10/ (24*60) 就是每10分鐘執行次
每天定時執行
每周定時執行
每月定時執行
每季度定時執行
每半年定時執行
每年定時執行
三、建立job方法
建立job,基本文法:
declare
begin
end;
使用dbms_job.submit方法過程,這個過程有五個參數:job、what、next_date、interval與no_parse。
dbms_job.submit(
job OUT binary_ineger,
What IN varchar2,
next_date IN date,
interval IN varchar2,
no_parse IN booean:=FALSE)
job參數是輸出參數,由submit()過程傳回的binary_ineger,這個值用來唯一辨別一個工作。一般定義一個變量接收,可以去user_jobs視圖查詢job值。
what參數是将被執行的PL/SQL代碼塊,存儲過程名稱等。
next_date參數指識何時将運作這個工作。
interval參數何時這個工作将被重執行。
no_parse參數訓示此工作在送出時或執行時是否應進行文法分析——true,預設值false。訓示此PL/SQL代碼在它第一次執行時應進行文法分析,而FALSE訓示本PL/SQL代碼應立即進行文法分析。
四、其他job相關的存儲過程
大緻介紹下這些過程:
1、broken()過程更新一個已送出的工作的狀态,典型地是用來把一個已破工作标記為未破工作。這個過程有三個參數:job、broken與next_date。
job參數是工作号,它在問題中唯一辨別工作。
broken參數訓示此工作是否将标記為破——true說明此工作将标記為破,而false說明此工作将标記為未破。
next_date參數訓示在什麼時候此工作将再次運作。此參數預設值為目前日期和時間。
job如果由于某種原因未能成功執行,oracle将重試16次後,還未能成功執行,将被标記為broken,重新啟動狀态為broken的job,有如下兩種方式;
a、利用dbms_job.run()立即執行該job
b、利用dbms_job.broken()重新将broken标記為false
2、change()過程用來改變指定job的設定。
這個過程有四個參數:job、what、next_date、interval。
這裡,
job參數是一個整數值,它唯一辨別此工作。
what參數是由此job運作的一塊PL/SQL代碼塊。
next_date參數訓示何時此job将被執行。
interval參數訓示一個job重執行的頻度。
3、interval()過程用來顯式地設定重複執行一個job之間的時間間隔數。
這個過程有兩個參數:job、interval。
job參數辨別一個特定的工作。
interval參數訓示一個工作重執行的頻度。
4、isubmit()過程用來用特定的job号送出一個job。
這個過程有五個參數:job、what、next_date、interval、no_parse。
這個過程與submit()過程的唯一差別在于此job參數作為IN型參數傳遞且包括一個由開發者提供的job号。如果提供的job号已被使用,将産生一個錯誤。
5、next_date()過程用來顯式地設定一個job的執行時間。這個過程接收兩個參數:job、next_date。
job辨別一個已存在的工作。
next_date參數訓示了此job應被執行的日期、時間。
6、remove()過程來删除一個已計劃運作的job。這個過程接收一個參數:
job參數唯一地辨別一個工作這個參數的值是由為此工作調用submit()過程傳回的job參數的值,已正在運作的job不能删除。
7、run()過程用來立即執行一個指定的job。這個過程隻接收一個參數:
procedure run(job INbinary_ineger)
job參數辨別将被立即執行的工作。
8、使用submit()過程,job被正常地計劃。
9、user_export()過程傳回一個指令,此指令用來安排一個存在的job以便此job能重新送出。此程式有兩個參數:job、my_call。
procedure user_export(
)
job參數辨別一個安排了的工作。
my_call參數包含在它的目前狀态重新送出此job所需要的正文。
10、what()過程應許在job執行時重新設定此正在運作的指令。這個過程接收兩個參數:job、what。
job參數辨別一個存在的工作。
what參數訓示将被執行的新的PL/SQL代碼。實作的功能:每隔一分鐘自動向getSysDate表中插入目前的系統時間。
五、示例
/ 每10秒鐘執行一次 插入一條時間 /
-- 建立table
-- 建立存儲過程
as
-- 調用過程測試
--select 24 60 60 from dual; --得出一天的秒數
-- 建立job
-- 運作job
-- 查詢是否插入資料
-- 删除一個job
六、關于設定job任務數量和控制并發
初始化相關參數job_queue_processes
job_queue_process表示oracle能夠并發的job的數量,sqlplus中可以通過語句
show parameterjob_queue_process; 來檢視oracle中job_queue_process的值。
select * fromv$parameter;
select name,description from v$bgprocess;
七、job不運作的大概原因
(1)、上面講解了job的參數:與job相關的參數一個是job_queue_processes,這個是運作job時候所起的程序數,當然系統裡面job大于這個數值後,就會有排隊等候的,最小值是0,表示不運作job,最大值是1000,在OS上對應的程序時SNPn,9i以後OS上管理job的程序叫CJQn。可以使用下面這個SQL确定目前有幾個SNP/CJQ在運作。
select * fromv$bgprocess,這個paddr不為空的snp/cjq程序就是目前空閑的程序,有的表示正在工作的程序。
另外一個是job_queue_interval,範圍在1--3600之間,機關是秒,這個是喚醒JOB的process,因為每次snp運作完他就休息了,需要定期喚醒他,這個值不能太小,太小會影響資料庫的性能。
先确定上面這兩個參數設定是否正确,特别是第一個參數,設定為0了,所有job就不會自動運作了。
(2)、使用下面的SQL檢視job的的broken,last_date和next_date,last_date是指最近一次job運作成功的結束時間,next_date是根據設定的頻率計算的下次執行時間,根據這個資訊就可以判斷job上次是否正常,還可以判斷下次的時間對不對,SQL如下:
有時候我們發現他的next_date是4000年1月1日,說明job要不就是在running,要不就是狀态是break(broken=Y),如果發現job的broken值為Y,找使用者了解一下,确定該job是否可以broken,如果不能broken,那就把broken值修改成N,修改再使用上面的SQL檢視就發現它的last_date已經變了,job即可正常運作,修改broken狀态的SQL如下:
(3)、使用下面的SQL查詢是否job還在running
如果發現job已經Run了很久了還沒有結束,就要查原因了。一般的jobrunning時會鎖定相關的相關的資源,可以檢視一下v$access和v$locked_object這兩個view。如果發現其他程序鎖定了與job相關的object,包括package/function/procedure/table等資源,那麼就要把其他程序删除,有必要的話,把job的程序也删除,再重新執行看看結果。
(4)、如果上面都正常,但是job還不run,怎麼辦?那我們要考慮把job程序重新開機一次,防止是SNP程序死了造成job不跑,指令如下:
alter system setjob_queue_processes = 0; --關閉job程序,等待5--10秒鐘
alter system setjob_quene_processes = 5; --恢複原來的值
(5)、Oracle的BUG:Oracle9i裡面有一個BUG,當計數器到497天時,剛好達到它的最大值,再計數就會變成-1,繼續計數就變成0了,然後計數器将不再跑了。如果碰到這種情況就得重新開機資料庫,但是其他的Oracle7345和Oracle8i的資料庫沒有發現這個問題。
(6)、資料庫上的檢查基本上就這多,如果job運作還有問題,那需要看一下是否是程式本身的問題,比如處理的資料量大,或者網絡速度慢等造成運作時過長,那就需要具體情況具體分析了。我們可以通過下面的SQL手工執行一下job看看:
JOB鎖處理方法:
找出正在執行的JOB編号及其會話編号
SELECT SID,JOB FROM DBA_JOBS_RUNNING;
停止該JOB的執行
SELECT SID,SERIAL# FROM V$SESSION WHERE SID='&SID';
ALTER SYSTEM KILL SESSION '&SID,&SERIAL';
EXEC DBMS_JOB.BROKEN(&JOB,TRUE);
執行個體分析:
1,查詢正在運作的Job,通過查詢有兩個,和程序占用較多的是兩個Oracle程序符合。
SQL> SELECT SID,JOB FROM DBA_JOBS_RUNNING;
SID JOB
---------- ----------
12 116
16 117
2,查詢正在運作的job的資訊
SQL> SELECT SID,SERIAL# FROM V$SESSION WHERE SID='12';
SID SERIAL#
12 4
SQL> SELECT SID,SERIAL# FROM V$SESSION WHERE SID='16';
16 1
3,利用查詢出來的job資訊将job結束掉
SQL> ALTER SYSTEM KILL SESSION '12,4';
System altered.
SQL> ALTER SYSTEM KILL SESSION '16,1';
4,如果不希望運作上述job的話,可以将job設定為broken.
EXEC DBMS_JOB.BROKEN(116,TRUE);
EXEC DBMS_JOB.BROKEN(117,TRUE);
根據個人經驗,這種方法并不會立即中斷job的運作。最好是找到job對應的線程kill掉。
删除JOB方法:注:BROKEN值如果為TRUE則為停用,FALSE為啟用,預設FALSE。
DBMS_JOB.BROKEN(JOB編号,TRUE);
dbms_job.remove(JOB編号);
commit;
頂
踩