求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
基于事件驱动的Oracle作业调度
 

发布于2012-4-11

 

对很多系统而言,作业调度event, 'Scheduler');" target="_self">Scheduler是不可缺少的部分。大数据量集中批量处理、OLAP数据聚集都需要利用业务空闲时段(如夜间)进行处理。Oracle自身提供了较为可靠的运行作业调度器机制,为我们提供了现成的Scheduler组件。

调度作业有两种大类型:基于时间(Time-Based)和基于事件(Event-Based)。基于时间的调度作业顾名思义,就是设置特定的时间调度规则。依据时间规则在特定的时间点触发执行代码程序。例如:每天夜间22:00执行数据聚合操作,生成聚合数据。在Oracle中,大部分的作业都是这种类型。比如从10G出现的统计信息收集作业,就是规定在工作日夜间22:00开始进行的基于时间作业。

基于事件的作业调度则是依据特定的事件场景。比如:在应用程序发生故障的时候,启动数据清理程序,将中间数据结果还原。这样的作业,调度时间是不确定的,依据具体的业务和程序场景。而且,基于事件作业执行的过程中,要具有作业的特性,也就是作业执行代码执行和触发作业程序之间是异步执行关系。

在Oracle中,我们可以方便的时候dbms_scheduler包进行基于时间作业的定义。同样,我们可以借助Oracle消息队列的特性,来实现Event Based作业类型。

1、原理和环境准备

为了更好说明问题,笔者选择Oracle 10R2作为实验环境,并且构建一个新的用户schema环境。

SQL> show user;

User is "SYS"

SQL> select * from v$version;

BANNER

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

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE 10.2.0.1.0 Production

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0–Production

创建一个新用户testuser,并授予相应的系统和角色权限。

SQL> create user testuser identified by testuser ;

User created

SQL> alter user testuser quota unlimited on users;

User altered

SQL> grant connect to testuser;

Grant succeeded

SQL> grant create table to testuser;

Grant succeeded

SQL> grant create sequence to testuser;

Grant succeeded

SQL> grant create type to testuser;

Grant succeeded

SQL> GRANTAQ_ADMINISTRATOR_ROLETO testuser;

Grant succeeded

SQL> GRANT CREATE JOB TO testuser;

Grant succeeded

只有设置了AQ_ADMINISTRATOR_ROLE角色,才能使用Oracle的Advanced Queue组件功能。

原理上:我们要利用Oracle的Advanced Queue组件的功能。要求在特定的Event发生时,我们需要向队列中传入一个标记对象。Scheduler会根据特定的标记对象标识来调用特定的作业Job代码程序。这样就实现了基本的Event Based Job。

2、日志插入作业

我们希望实现一个功能,就是在特定事件发生的时候,会向数据表中插入一条记录。

首先,我们准备代码数据表。

SQL> conn testuser/testuser@ots;

Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.1.0

Connected as testuser

SQL> create sequence seq_test;

Sequence created

SQL> create table test_log (id number not null, comments varchar2(100), created date);

Table created

SQL> alter table test_log add constraint pk_test primary key (id);

Table altered

我们创建了日志数据表。当触发事件的时候,直接向该数据表中插入一条记录。

3、配置调度作业

首先,需要定义一个类型type,用于向AQ中触发作业。该type相当于事件发生的信息单元。

SQL> create or replace type t_event_que_payload as object (event_name varchar2(30));

2 /

Type created

创建事件表,用来记录消息队列AQ中消息信息。

SQL> exec dbms_aqadm.create_queue_table(queue_table => 'event_queue_table',queue_payload_type => 't_event_que_payload',multiple_consumers => true,comment => 'Test Event Queue');

PL/SQL procedure successfully completed

使用dbms_aqadm方法create_queue_table中,两个最重要的参数:queue_table是创建消息表的名称,queue_payload_type则是规定了队列中存放对象的type类型。

执行后,的确创建了数据表event_queue_table。

SQL> desc event_queue_table;

Name     Type     Nullable DefaultComments

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

Q_NAME     VARCHAR2(30)     Y

MSGID RAW(16)

CORRID VARCHAR2(128) Y

PRIORITY NUMBER Y

(篇幅原因,有省略……)

下面需要创建队列对象,单独执行出队列名称和队列数据表名称。

SQL> exec dbms_aqadm.create_queue(queue_name => 'event_queue',queue_table => 'event_queue_table');

PL/SQL procedure successfully completed

SQL> select name, queue_table, qid, queue_type,user_comment from user_queues;

NAME     QUEUE_TABLE     QID     QUEUE_TYPE     USER_COMMENT

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

EVENT_QUEUE     EVENT_QUEUE_TABLE     111623     NORMAL_QUEUE

AQ$_EVENT_QUEUE_TABLE_E     EVENT_QUEUE_TABLE     111622     EXCEPTION_QUEUE exception queue

注意,为了队列AQ,Oracle要创建出多个数据表,用于进行不同的消息存储。同时,处于性能等多方面的考量,很多这样的数据表是采用IOT(Index-Organized Table)结构的。

SQL> select table_name, tablespace_name, iot_name,iot_type from user_tables;

TABLE_NAME     TABLESPACE_NAME     IOT_NAME     IOT_TYPE

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

TEST_LOG         USERS

EVENT_QUEUE_TABLE USERS

AQ$_EVENT_QUEUE_TABLE_S USERS

SYS_IOT_OVER_111613 USERS AQ$_EVENT_QUEUE_TABLE_G IOT_OVERFLOW

AQ$_EVENT_QUEUE_TABLE_I IOT

AQ$_EVENT_QUEUE_TABLE_G IOT

AQ$_EVENT_QUEUE_TABLE_H IOT

AQ$_EVENT_QUEUE_TABLE_T IOT

8 rows selected

最后,启动创建出的AQ队列event_queue。

SQL> EXEC DBMS_AQADM.start_queue (queue_name => 'event_queue');

PL/SQL procedure successfully completed

注意,此时队列状态开启为可用。

SQL> select name, queue_table, qid, queue_type,ENQUEUE_ENABLED, DEQUEUE_ENABLED from user_queues;

NAME     QUEUE_TABLE     QID     QUEUE_TYPE     ENQUEUE_ENABLED     DEQUEUE_ENABLED

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

EVENT_QUEUE     EVENT_QUEUE_TABLE     111623     NORMAL_QUEUE     YES     YES

AQ$_EVENT_QUEUE_TABLE_E EVENT_QUEUE_TABLE 111622 EXCEPTION_QUEUE NO NO

队列创建到此结束。下面创建作业,使用dbms_scheduler方法。

SQL> begin

2 dbms_scheduler.create_job(job_name => 'event_based_job',

3 job_type => 'PLSQL_BLOCK',

4 job_action => 'begin

5 insert into test_log values (seq_test.nextval, ''TT'', sysdate);

6 commit;

7 end;

8 ',

9 start_date=>systimestamp,

10 event_condition => 'tab.user_data.event_name = ''test_signal''',

11 queue_spec => 'event_queue',

12 enabled => TRUE);

13 end;

14 /

PL/SQL procedure successfully completed

SQL> select job_name, job_creator from user_scheduler_jobs;

        JOB_NAME         JOB_CREATOR

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

        EVENT_BASED_JOB         TESTUSER

注意包方法的几个主要参数。Job_name定义了新增加job的名称。Job_action定义了当这个Job被触发的时候,需要执行哪段代码。Event_condition规定了调度数据对象值为’test_signal’的时候才会执行这个作业。Queue_spec制定了监视事件的队列名称。

4、测试作业情况

我们模拟向队列中插入事件消息对象的场景。

SQL> DECLARE

2 l_enqueue_options DBMS_AQ.enqueue_options_t;

3 l_message_properties DBMS_AQ.message_properties_t;

4 l_message_handle RAW(16);

5 l_queue_msg t_event_que_payload;

6 BEGIN

7 l_queue_msg :=t_event_que_payload('test_signal'); --创建事件event消息对象;

8

9 DBMS_AQ.enqueue(queue_name =>'event_queue',

10 enqueue_options => l_enqueue_options,

11 message_properties => l_message_properties,

12 payload =>l_queue_msg,

13 msgid => l_message_handle);

14 COMMIT;

15 END;

16 /

PL/SQL procedure successfully completed

在实际使用的时候,只需要向AQ队列中插入消息体。Oracle就可以根据消息的内容调用特定的作业。观察结果:

--作业效果;

SQL> select * from test_log;

         ID     COMMENTS     CREATED

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

    1     TT             2012/1/29 1

--作业执行记录;

SQL> col job_name for a20;

SQL> select log_date, job_name, job_class, status from user_scheduler_job_log;

LOG_DATE     JOB_NAME      JOB_CLASS      STATUS

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

29-1月 -12     01.43.47.     EVENT_BASED_JOB     DEFAULT_JOB_CLASS     SUCCEEDED

484000     下午     +08:00

5、结论

event_based作业类型,在实际中出现的机率并不是很高。主要是一些数据现场恢复和清理工作。使用Oracle的AQ和调度器机制,我们可以方便的将这种类型作业加以实现。


相关文章 相关文档 相关视频



我们该如何设计数据库
数据库设计经验谈
数据库设计过程
数据库编程总结
数据库性能调优技巧
数据库性能调整
数据库性能优化讲座
数据库系统性能调优系列
高性能数据库设计与优化
高级数据库架构师
数据仓库和数据挖掘技术
Hadoop原理、部署与性能调优

 
分享到
 
 
     


MySQL索引背后的数据结构
MySQL性能调优与架构设计
SQL Server数据库备份与恢复
让数据库飞起来 10大DB2优化
oracle的临时表空间写满磁盘
数据库的跨平台设计
更多...   


并发、大容量、高性能数据库
高级数据库架构设计师
Hadoop原理与实践
Oracle 数据仓库
数据仓库和数据挖掘
Oracle数据库开发与管理


GE 区块链技术与实现培训
航天科工某子公司 Nodejs高级应用开发
中盛益华 卓越管理者必须具备的五项能力
某信息技术公司 Python培训
某博彩IT系统厂商 易用性测试与评估
中国邮储银行 测试成熟度模型集成(TMMI)
中物院 产品经理与产品管理
更多...