用于Oracle容灾和RAC的测试代码
因为工作关系,在测试一些软件或演示时,需要一段能很清楚的演示容灾和RAC的自动切换效果的代码.发现达到满意的效果还是有些技巧的. DBMS_OUTPUT并不能实时的反应出效果.而Oracle的管道反而正合用,所以后面整理了下.效果还比较满意.
效果如下:
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;
/至此,应当就能得到想要的效果了。
- 01-11全球最受赞誉公司揭晓:苹果连续九年第一
- 12-09罗伯特·莫里斯:让黑客真正变黑
- 12-09谁闯入了中国网络?揭秘美国绝密黑客小组TA
- 12-09警示:iOS6 惊现“闪退”BUG
- 11-18LG新能源宣布与Bear Robotics达成合作,成为
- 11-18机构:三季度全球个人智能音频设备市场强势
- 11-18闲鱼:注册用户过6亿 AI技术已应用于闲置交
- 11-18美柚、宝宝树回应“涉黄短信骚扰”:未发现
- 11-01京东七鲜与前置仓完成融合