一、回顧
調度分基於時間的調度和基於事件的調度。
稍微復習一下前面的只是請浏覽:《ORACLE調度之基於時間的調度(一)【weber出品】》
二、知識補充
1、隊列:一種數據結構,就像一根管道一樣,進程一個個的塞進去,然後一個個的出來,講究的是先進先出。
2、高級隊列:
a、高級隊列管理是Oracle數據庫的一個特性,它提供消息隊列管理功能。這是一個非常可靠、安全和可伸縮的消息管理系統,因為它使用與其他基於Oracle技術的應用程序相同的數據庫特性。
b、高級隊列管理的一個很大優點是它可以通過PL/SQL、Java或C來訪問,這樣你就可以把來自一個Java servlet的消息入隊列和使PL/SQL存儲過程中的相同消息出隊列。
c、高級隊列管理的另一個優點是你可以利用這一軟件通過Oracle Net Services (SQL*Net)、HTTP(S)和SMTP,在遠程節點之間傳播消息。高級隊列甚至可以通過消息網關與非Oracle的消息管理系
統(如IBM MQSeries)相集成。
d、Oracle高級隊列管理提供了單消費者隊列和多消費者隊列。單消費者隊列只面向單一的接收者。多消費者隊列可以被多個接收者使用。當把消息放入多消費者隊列時,應用程序的程序員必須顯式地在消息屬性中指定這些接收者,或者建立決定每條消息的接收者的基於規則的訂閱過程。
三、基於事件的調度
創建測試用表
conn hr/hr create table event_job_test(id number,createdatae date); alter table event_job_test add constraint pk_event_job_test primary key(id); create sequence seq_event_job_test;
創建一個類型:
create or replace type t_event_queue as object(object_owner varchar2(50),event_name varchar2(50));
創建一個隊列表,該隊列包含的字段就是我們剛才創建的類型t_event_queue所包含的屬性。
conn /as sysdba grant execute on dbms_aqadm to hr; conn hr/hr begin dbms_aqadm.create_queue_table( queue_table=>'event_queue_tab', queue_payload_type=>'t_event_queue', multiple_consumers=>true); end; /
創建一個隊列,並將該隊列與前面創建的隊列表關聯
begin dbms_aqadm.create_queue( queue_name=>'event_queue', queue_table=>'event_queue_tab'); end; /
啟動隊列
begin dbms_aqadm.start_queue(queue_name=>'event_queue'); end; /
創建一個基於事件的任務
conn /as sysdba BEGIN sys.dbms_scheduler.create_job( job_name => '"HR"."EVENT_BASE_JOB"', job_type => 'PLSQL_BLOCK', job_action => 'begin insert into hr.event_job_test values(seq_event_job_test.nextval,sysdate); commit; end;', event_condition => 'tab.user_data.object_owner=''HR'' and tab.user_data.event_name=''give_me_an_event''', queue_spec => 'HR.EVENT_QUEUE', start_date => systimestamp at time zone '+8:00', job_class => 'DEFAULT_JOB_CLASS', auto_drop => FALSE, enabled => TRUE); END;
向隊列中插入消息
沒插入之前,查詢表,發現沒數據。
conn hr/hr select * from event_job_test;
向隊列裡插入消息
conn /as sysdba grant execute on dbms_aq to hr; conn hr/hr declare l_enqueue_options dbms_aq.enqueue_options_t; l_message_properties dbms_aq.message_properties_t; l_message_handle raw(16); l_queue_msg t_event_queue; begin l_queue_msg := t_event_queue('HR','give_me_an_event'); dbms_aq.enqueue( queue_name=>'event_queue', enqueue_options=>l_enqueue_options, message_properties=>l_message_properties, payload=>l_queue_msg, msgid=>l_message_handle); commit; end; select * from event_job_test;
刪除作業:
begin dbms_scheduler.drop_job(job_name => '"HR"."EVENT_BASE_JOB"', force => true); end;
創建基於事件的調度加載數據
創建測試用表
conn scott/tiger create table t as select * from emp where 1=2; vi /u01/load.ctl load data infile '/u01/data.txt' badfile '/u01/bad.emp' discardfile '/u01/discadr.emp' truncate into table t fields terminated by ',' trailing nullcols (EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) vi /u01/load.sh #!/bin/bash export ORACLE_BASE=/u01/app/oracle export ORACLE_HOME=$ORACLE_BASE/product/11.2/db_1 export ORACLE_SID=orcl $ORACLE_HOME/bin/sqlldr scott/tiger control=/u01/load.ctl log=/u01/load.log
保存退出
chmod +x /u01/load.sh
將emp中的數據轉儲到/u01/data.txt中:
set trims on spool /u01/data.txt select EMPNO||','|| ENAME||','|| JOB||','|| MGR||','|| HIREDATE||','|| SAL||','|| COMM||','|| DEPTNO from emp; spool off
創建一個類型:
sqlplus scott/tiger create or replace type t_event_queue as object ( object_owner varchar2(10), object_name varchar2(20), event_type varchar2(20), event_timestamp number(2) ); /
創建一個隊列表,該隊列包含的字段就是我們剛才創建的類型t_event_queue所包含的屬性。
conn /as sysdba grant execute on dbms_aqadm to scott; conn scott/tiger begin dbms_aqadm.create_queue_table( queue_table=>'event_queue_tab', queue_payload_type=>'t_event_queue', multiple_consumers=>true); end; /
創建一個隊列,並將該隊列與前面創建的隊列表關聯
begin dbms_aqadm.create_queue( queue_name=>'event_queue', queue_table=>'event_queue_tab'); end; /
啟動隊列
begin dbms_aqadm.start_queue(queue_name=>'event_queue'); end; /
創建一個基於事件的任務
conn /as sysdba BEGIN sys.dbms_scheduler.create_job(job_name => '"SYS"."PERFORM_DATA_LOAD"', --屬主必須是sys job_type => 'EXECUTABLE', job_action => '/u01/load.sh', event_condition => 'tab.user_data.object_owner = ''SCOTT'' and tab.user_data.object_name = ''DATA.TXT'' and tab.user_data.event_type = ''FILE_ARRIVAL'' and tab.user_data.event_timestamp < 9',--創建一個作業,如果成批裝入的數據文件在上午 9:00 之前到達文件系統,則運行此作業 queue_spec => 'SCOTT.EVENT_QUEUE', start_date => systimestamp at time zone '+8:00', job_class => 'DEFAULT_JOB_CLASS', auto_drop => FALSE, enabled => TRUE); END; /
向隊列中插入消息
conn scott/tiger select * from t;
向隊列裡插入消息
conn /as sysdba grant execute on dbms_aq to scott; conn scott/tiger declare l_enqueue_options dbms_aq.enqueue_options_t; l_message_properties dbms_aq.message_properties_t; l_message_handle raw(16); l_queue_msg t_event_queue; begin l_queue_msg := t_event_queue('SCOTT', 'DATA.TXT', 'FILE_ARRIVAL',8); dbms_aq.enqueue(queue_name => 'event_queue', enqueue_options => l_enqueue_options, message_properties => l_message_properties, payload => l_queue_msg, msgid => l_message_handle); commit; end; / select * from t;
刪除作業:
conn /as sysdba begin dbms_scheduler.drop_job(job_name => '"SYS"."PERFORM_DATA_LOAD"', force => true); end; /
總結一下oracle db裡用job調度shell的注意點:
1、shell腳本裡開頭要加#!/bin/bash等指定使用的shell類型
2、所有相關環境變量都得在shell裡明確指定
3、如果要寫入文件必需使用絕對路徑
4、使用sys用戶建立job
1。任務調度計劃由操作系統,如計劃和任務的Windows,Linux和UNIX的crontab任務調度機制
一些數據庫本身的任務調度,如Oracle的工作任務調度機制
1、dbwn會將數據塊從buffer cache寫入數據文件,對應的塊僅僅會從lruw鏈上摘下去,oracle dbwn是按照lruw鏈來寫髒塊的這句話是不對的,dbwn進程是按照ckeckpoint鏈上的數據塊順序來寫數據塊。
2、檢查點發生的時候肯定會調度dbwn來寫檢查點列隊(checkpoint鏈)上的髒數據塊,目前檢查點又分為增量檢查點和完全檢查點,完全檢查點會在alter system checkpoint和一致性關閉數據庫的時候觸發,會把checkpoint鏈上所有髒數據塊都寫入數據庫。而增量檢查點做了什麼呢?增量檢查點會把checkpoint鏈上第一個塊的lrba地址寫入控制文件,lrba對應的是checkpoint鏈上第一個數據塊第一次修改的那個操作所對應日志的位置,同時checkpoint鏈上從鏈頭開始的一部分數據塊寫入數據文件(checkpoint鏈上的數據塊是嚴格按照修改時間的順序來排列的,並且如果對同一個塊做了多次修改,checkpoint鏈上也只有這一個塊,可以認為多次修改記錄都在這一個數據塊上,並不是像你說的檢查點隊列上掛的只是這個塊的第一次被修改時的數據塊,這裡我也不是太理解你的意思),數據塊寫入數據文件自然就需要dbwn進程(這裡是檢查點進程觸發了dbwn),而dbwn寫髒數據之前lgwr會做什麼呢?lgwr會先把對應的日志寫入redo.log。也就是dbwn會觸發lgwr,oracle就是這樣,寫數據之前必然先寫日志,有日志數據就是安全的。
3、lrba是用來干什麼的呢?比如發生增量檢查點,記錄lrba地址到控制文件,觸發dbwn,要從checkpoint鏈上摘掉5個塊,摘掉之前dbwn觸發lgwr先把這五個塊對應操作的日志寫入redo.log,有日志了,但是在這個時候(dbwn還沒有將這5個髒數據塊寫入數據文件時侯)數據庫崩潰了,buffer cache中數據都丟了,下次打開數據庫的時候。smon進程會檢查數據文件的end scn,如果為空就是數據庫沒有正常關閉(這裡你可以看看實例恢復的原理,就不多說了),這個時候就要實例恢復,所以就會定位一個恢復點,lrba地址就是這個恢復的點,需要把剛剛以寫日志的5個塊重新在buffer cache中構造出來,lrba地址就是這個作用,但是實例恢復的具體情況還分很多,可以看看相關書籍。
希望可以幫助你。