专栏首页小麦苗的DB宝专栏【DB笔试面试480】 RAC中如何指定JOB的运行实例?

【DB笔试面试480】 RAC中如何指定JOB的运行实例?

题目部分

RAC中如何指定JOB的运行实例?

答案部分

在RAC中,可以让JOB在某个指定的实例上运行。对于DBMS_JOB和DBMS_SCHEDULER来说,它们的指定方法不同:

(1)在DBMS_JOB下,在执行SYS.DBMS_JOB.SUBMIT包创建JOB的时候,可以指定INSTANCE参数,该参数指定了JOB运行的实例。在RAC环境中,采用DBMS_JOB包可以指定JOB运行时候的实例。

示例代码如下所示,该例子展示了获取RAC数据库的IP地址并记录到临时表T_IPADDRESS_LHR中,例子很经典,希望读者可以理解。

1) 创建临时表用于记录RAC数据库的IP地址

DROP TABLE T_IPADDRESS_LHR;
CREATE TABLE T_IPADDRESS_LHR(INST_ID NUMBER, HOST_NAME VARCHAR2(255), HOST_IP  VARCHAR2(255) );

2) 创建视图VH_IPADDRESS_LHR用于从V$DIAG_ALERT_EXT中获取IP地址

CREATE OR REPLACE VIEW VH_IPADDRESS_LHR AS  
SELECT A.HOST_ID || ': ' || A.HOST_ADDRESS HOST_IP1,
       A.HOST_ADDRESS HOST_IP2,
  A.HOST_ID HOST_NAME2
        FROM V$DIAG_ALERT_EXT A
       WHERE A.COMPONENT_ID = 'RDBMS'
         AND UPPER(A.FILENAME) =
             (SELECT UPPER(SUBSTR(D.VALUE, 1, (LENGTH(D.VALUE) - 5)) ||
                           'ALERT' || SUBSTR(D.VALUE, -6, 1) || 'LOG.XML')
                FROM V$PARAMETER D
               WHERE D.NAME = 'BACKGROUND_DUMP_DEST')
         AND A.INDX =
             (SELECT MAX(B.INDX)
                FROM V$DIAG_ALERT_EXT B
               WHERE B.COMPONENT_ID = 'RDBMS'
                 AND UPPER(B.FILENAME) =
                     (SELECT UPPER(SUBSTR(D.VALUE, 1, (LENGTH(D.VALUE) - 5)) ||
                                   'ALERT' || SUBSTR(D.VALUE, -6, 1) ||
                                   'LOG.XML')
                        FROM V$PARAMETER D
                       WHERE D.NAME = 'BACKGROUND_DUMP_DEST'));
/

3) 创建存储过程用于在指定的实例上运行程序,首先从函数UTL_INADDR.GET_HOST_ADDRESS中获取,若是系统没有该包,则从视图VH_IPADDRESS_LHR中获取IP地址

CREATE OR REPLACE PROCEDURE PH_IP_LHR AS
  V_SQL VARCHAR2(4000);
BEGIN
  INSERT INTO T_IPADDRESS_LHR
    (INST_ID, HOST_NAME)
    SELECT V.INSTANCE_NUMBER, V.HOST_NAME FROM V$INSTANCE V;
  COMMIT;
  V_SQL := 'UPDATE T_IPADDRESS_LHR T
     SET T.HOST_IP = UTL_INADDR.GET_HOST_ADDRESS
   WHERE T.INST_ID = USERENV(''INSTANCE'')';
  EXECUTE IMMEDIATE V_SQL;
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    V_SQL := 'UPDATE T_IPADDRESS_LHR T
       SET T.HOST_IP =
           (SELECT V.HOST_IP2 FROM VH_IPADDRESS_LHR V)
     WHERE T.INST_ID = USERENV(''INSTANCE'')';
    EXECUTE IMMEDIATE V_SQL;
    COMMIT;
END PH_IP_LHR;
/

4) 创建JOB来获取IP地址

DECLARE
  X NUMBER;
BEGIN
  FOR CUR IN (SELECT B.JOB
                FROM DBA_JOBS B
               WHERE B.WHAT = 'PH_IP_LHR;') LOOP
    SYS.DBMS_IJOB.REMOVE(CUR.JOB);
    COMMIT;
  END LOOP;
  FOR CUR IN (SELECT B.INST_ID FROM GV$INSTANCE B) LOOP
    SYS.DBMS_JOB.SUBMIT(JOB       => X,
                        WHAT      => 'PH_IP_LHR;',
                        NEXT_DATE => SYSDATE+CUR.INST_ID/8640,
                        INTERVAL  => 'NULL',
                        NO_PARSE  => FALSE,
                        INSTANCE  => CUR.INST_ID);
    COMMIT;
  END LOOP;
END;
/

(2)DBMS_SCHEDULER下指定实例运行JOB稍微有点复杂,首先创建SERVICE,再创建JOB_CLASS,最后创建JOB才可以,具体过程可以参考如下案例的代码。

该例子和上面的DBMS_JOB例子一样展示了获取集群数据库的IP地址并记录到临时表T_IPADDRESS_LHR中,例子的前3步和上面的例子一样,不再赘述,接下来就是创建SERVICE和JOB_CLASS,最后是创建JOB的过程。

BEGIN
  FOR CUR IN (SELECT V.INST_ID,
                     V.INSTANCE_NAME,
                     'INST_LHR_' || V.INST_ID SERVICE_NAME,
                     'LHR_RAC' || V.INST_ID || '_JOB_CLASS' JOB_CLASS_NAME,
                     'RAC_LHR_' || V.INST_ID JOB_NAME
                FROM GV$INSTANCE V) LOOP
    BEGIN
      DBMS_SERVICE.STOP_SERVICE(SERVICE_NAME  => CUR.SERVICE_NAME,
                                INSTANCE_NAME => CUR.INSTANCE_NAME);
      DBMS_SERVICE.DELETE_SERVICE(SERVICE_NAME => CUR.SERVICE_NAME);
    EXCEPTION
      WHEN OTHERS THEN
        NULL;
    END;
    BEGIN
      DBMS_SCHEDULER.DROP_JOB_CLASS(JOB_CLASS_NAME => CUR.JOB_CLASS_NAME,
                                    FORCE          => TRUE);
    EXCEPTION
      WHEN OTHERS THEN
        NULL;
    END;
    BEGIN
      DBMS_SCHEDULER.DROP_JOB(JOB_NAME => CUR.JOB_NAME, FORCE => TRUE);
    EXCEPTION
      WHEN OTHERS THEN
        NULL;
    END;
  END LOOP;
  FOR CUR IN (SELECT V.INST_ID,
                     V.INSTANCE_NAME,
                     'INST_LHR_' || V.INST_ID SERVICE_NAME,
                     'LHR_RAC' || V.INST_ID || '_JOB_CLASS' JOB_CLASS_NAME,
                     'RAC_LHR_' || V.INST_ID JOB_NAME
                FROM GV$INSTANCE V) LOOP
    DBMS_SERVICE.CREATE_SERVICE(SERVICE_NAME => CUR.SERVICE_NAME,
                                NETWORK_NAME => CUR.SERVICE_NAME);
    DBMS_SERVICE.START_SERVICE(SERVICE_NAME  => CUR.SERVICE_NAME,
                               INSTANCE_NAME => CUR.INSTANCE_NAME);
    DBMS_SCHEDULER.CREATE_JOB_CLASS(JOB_CLASS_NAME => CUR.JOB_CLASS_NAME,
                                    SERVICE        => CUR.SERVICE_NAME);
    DBMS_SCHEDULER.CREATE_JOB(JOB_NAME    => 'RAC_LHR_' || CUR.INST_ID,
                              JOB_TYPE        => 'STORED_PROCEDURE',
                              JOB_ACTION      => 'PH_IP_LHR',
                              REPEAT_INTERVAL => NULL, --'FREQ=MINUTELY;INTERVAL=1'
                              JOB_CLASS       => CUR.JOB_CLASS_NAME,
                              END_DATE        => NULL,
                              ENABLED         => TRUE);
  END LOOP;
END;
/

& 说明:

有关具体的操作过程可以参考我的BLOG:http://blog.itpub.net/26736162/viewspace-2072635/

本文选自《Oracle程序员面试笔试宝典》,作者:李华荣。

本文分享自微信公众号 - DB宝(xiaomaimiaolhr),作者:小麦苗best

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-03-31

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【DB笔试面试563】在Oracle中,什么是聚簇因子(Clustering Factor)?

    Oracle数据库中最普通、最为常用的即为堆表,堆表的数据存储方式为无序存储,当对数据进行检索的时候,非常消耗资源,这个时候就可以为表创建索引了。在索引中,数据...

    小麦苗DBA宝典
  • 【DB笔试面试559】在Oracle中,降序索引和升序索引分别是什么?

    对于升序索引(Ascending Indexes),数据库按升序排列的顺序存储数据。索引默认按照升序存储列值。默认情况下,字符数据按每个字节中包含的二进制值排序...

    小麦苗DBA宝典
  • 【DB笔试面试572】在Oracle中,模糊查询可以使用索引吗?

    (1)若SELECT子句只检索索引字段,那么模糊查询可以使用索引,例如,“SELECT ID FROM TB WHERE ID LIKE '%123%';”可以...

    小麦苗DBA宝典
  • 开篇:预备知识---1

    ​ 大家好,好久不写博客了,久违的感觉。这篇文章是 C/C++ 程序设计专栏的第一篇文章。说实话这个专栏申请了有半年多了,但是到目前为止仍然没有文章产出,本来...

    指点
  • 『高级篇』docker之Mesos微服务部署(26)

    PS:基本的mesos和marathon讲述完成了,因为主机内存后面的结果没有演示但是基本的命令和镜像有了后面基本是,基本操作啦!下次一起学学docker sw...

    IT故事会
  • 【DB笔试面试479】Oracle JOB分为哪几类?

    Oracle的JOB分为两类,DBMS_JOB和DBMS_SCHEDULER,二者都可以完成定时任务。

    小麦苗DBA宝典
  • new 运算符的原理

    (2)使用指定的参数调用构造函数 Foo,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数时,Foo 不带任何...

    Leophen
  • Java并发-24.原子操作类

    java.util.concurrent.atomic包中有13个原子类,属于四种类型 的跟新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新...

    悠扬前奏
  • Shell脚本循环读取文件中的每一行

    While循环中read命令从标准输入中读取一行,并将内容保存到变量line中。在这里,-r选项保证读入的内容是原始的内容,意味着反斜杠转义的行为不会发生。输入...

    卡尔曼和玻尔兹曼谁曼
  • 看完你就应该能明白的悲观锁和乐观锁

    Java 按照锁的实现分为乐观锁和悲观锁,乐观锁和悲观锁并不是一种真实存在的锁,而是一种设计思想,乐观锁和悲观锁对于理解 Java 多线程和数据库来说至关重要,...

    cxuan

扫码关注云+社区

领取腾讯云代金券