0
点赞
收藏
分享

微信扫一扫

用于Oracle容灾和RAC的测试代码


         因为工作关系,在测试一些软件或演示时,需要一段能很清楚的演示容灾和RAC的自动切换效果的代码.发现达到满意的效果还是有些技巧的. DBMS_OUTPUT并不能实时的反应出效果.而Oracle的管道反而正合用,所以后面整理了下.效果还比较满意.

效果如下:

用于Oracle容灾和RAC的测试代码_Oracle容灾

用于Oracle容灾和RAC的测试代码_Oracle容灾_02



1. 定义一个用于返回运行状态的自定义类型

--定义类型
CREATE OR REPLACE TYPE obj_tab_demo AS OBJECT (
id number,
timesta TIMESTAMP(6) WITH TIME ZONE,
inst VARCHAR2(16),
insthost VARCHAR2(64)
);
--实例化
CREATE OR REPLACE TYPE o_tab_demo AS TABLE OF obj_tab_demo ;

  小技巧:


    如果你已经执行了,想重建会报 ORA-02303 错误,11g虽有个force,并不好用.删除重建好了.


drop type  o_tab_demo   


drop type  obj_tab_demo  


要注意,此时用到这个类型的相关对象状态是失效的.


2. 创建存储过程

  -- 相关知识:


  -- Oracle管道化表函数 可以返回整个行的集.


  -- 管道化表函数必须返回一个集合,在函数中,PIPE ROW语句 被用来返回该集合


   --的个元素,此函数必须以一个空的RETURN语句结束,以表明它已经完成.


CREATE OR REPLACE FUNCTION fun_demo(p_num NUMBER)
RETURN o_tab_demo
PIPELINED
IS
v_instname varchar2(16);
v_hostname varchar2(64);
v_obj obj_tab_demo;
BEGIN
FOR i in 1 ..p_num LOOP
--实例序号
v_inst := userenv('instance');
-- 主机名
v_hostname := sys_context('userenv','host') ;
-- 可以从v$instance视图中找,也可按上面的方法找出
-- SELECT instance_name,host_name into v_instname,v_hostname FROM v$instance;
v_obj := obj_tab_demo(i,systimestamp,v_instname, v_hostname ); --systimestamp
PIPE ROW(v_obj);
END LOOP;
RETURN;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||' '||SUBSTR(SQLERRM,1,200));
END;

       --附注:


        -- 如果想保存结果或要求测试INSERT,可以创建一个DEMO表,关在函数中将序号,时间和当前实例都存进去,需要用自治事务处理.


--DEMO表结构 :
create table demo
(
id number,
timesta TIMESTAMP(6) WITH TIME ZONE,
inst VARCHAR2(16),
insthost VARCHAR2(64)
)

3. 在PL/SQL Developer或SQLPlus中运行测试    


    a. 得到当前session ID,用处在于,你输入的循环值太大,手工中断时会用到.


       SELECT DISTINCT(SID) INTO v_sessionsid FROM V$MYSTAT;      


    b. 打开output和运行时间开关


        set serveroutput on


        set timing on


    c.  在SQL查询中使用TABLE操作符来使Oracle函数返回Table集合   

col  id for a8
col inst for a10
col timesta for a40
col insthost for a10
SELECT * FROM TABLE( fun_demo(10000) );

 4. 如果你认为你已达到测试目地,就可以强行中止未运行完的SELECT了.

        如放在工具中执行,很简单,直接在菜单中选择相关项中止即可.


        如需手工方式中止,按下面的方法:


        a.找出会话ID和序列号,并得到kill命令         

select s.username, s.osuser,
s.sid, s.serial#,
p.spid, s.program,
s.STATUS,
'alter system kill session '||''''||s.sid||','||s.serial#||',@1'';' as oracle_kill
from v$session s,v$process p
where s.paddr = p.addr and s.username is not null
and s.sid = 上面查出的session id;

  b.然后运行  oracle_kill  杀掉会话即可.


5. 统计时间误差,看切换时间.这个是重点

    找出上面实时输出的时间点,找到所要的切换时间点,分别给time1和time2 变量.


    再运行下面代码,得到时间差.


    代码:


DECLARE
v_time1 TIMESTAMP(6) WITH TIME ZONE;
v_time2 TIMESTAMP(6) WITH TIME ZONE;
v_seconds NUMBER;
v_minutes NUMBER;
v_hours NUMBER;
v_days NUMBER;
v_weeks NUMBER;
BEGIN
v_time1 := '13-12月-13 10.22.31.765000 上午 +08:00';
v_time2 := '13-12月-13 10.23.04.546000 上午 +08:00';
SELECT substr((v_time2-v_time1),instr((v_time2-v_time1),' ')+7,2) seconds,
substr((v_time2-v_time1),instr((v_time2-v_time1),' ')+4,2) minutes,
substr((v_time2-v_time1),instr((v_time2-v_time1),' ')+1,2) hours,
trunc(to_number(substr((v_time2-v_time1),1,instr(v_time2-v_time1,' '))))  days,
trunc(to_number(substr((v_time2-v_time1),1,instr(v_time2-v_time1,' ')))/7) weeks
INTO v_seconds,v_minutes,v_hours,v_days,v_weeks
FROM dual;
DBMS_OUTPUT.PUT_LINE('-------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('begin: '||v_time1);
DBMS_OUTPUT.PUT_LINE('end : '||v_time2);
DBMS_OUTPUT.PUT_LINE('-------------------------------------------------');
DBMS_OUTPUT.PUT_LINE('seconds : '||v_seconds);
DBMS_OUTPUT.PUT_LINE('minutes : '||v_minutes);
DBMS_OUTPUT.PUT_LINE('hours : '||v_hours);
DBMS_OUTPUT.PUT_LINE('days : '||v_days);
DBMS_OUTPUT.PUT_LINE('weeks : '||v_weeks);
DBMS_OUTPUT.PUT_LINE('-------------------------------------------------');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLCODE||' '||SUBSTR(SQLERRM,1,200));
END;
/

至此,应当就能得到想要的效果了。


举报

相关推荐

0 条评论