分类: DB2/Informix
2005-07-11 10:56:45
4.2.6. 增加连接成员:
执行picc21 上$INformIXDIR/cdr/crtmeb.sh
脚本内容如下: TuhdxFz&
cdr define server -s datadbs -r datadbs -A /tmp/ats -R /tmp/ris
--connect=grp_ibm500 --init --sync=grp_picc21 grp_ibm500
注:确保ibm500 上的datadbs 和datadbs 已建立
确保ibm500 上的/tmp/ats 和/tmp/ris 目录已建立
4.2.7. 确定成员已连接
执行picc21 上执行cdr list server
系统显示如下说明新成员已连接:
SERVER ID STATE STATUS CONNECTION CHANGED
grp_ibm500 2 Active Connected Dec 7 14:54:17 2001
grp_picc21 1 Active Local
1. 在增加一个成员时也会在ibm500 上的database server 上建立一个名为
syscdr 的database,因此除了用cdr list server 外,也可以用dbaccess 命
令看是否建立了syscdr 来确定一个成员是否正确加入。
2. 确保picc21 和ibm500 已做时间同步(参见附录)
4.2.8. 定义replicate
执行picc21 上$INformIXDIR/cdr/repdef.sh
脚本内容如下: Zq/
cdr def repl picc2_a_charge_ratio -C ignore -S row -T -R "PO
picc2@grp_picc21:cbps.a_charge_ratio" "select *
from a_charge_ratio" "RO
picc2@grp_ibm500:cbps.a_charge_ratio" "select *
from a_charge_ratio"
cdr def repl picc2_a_comm_ratio -C ignore -S row -T -R "PO
picc2@grp_picc21:cbps.a_comm_ratio" "select *
from a_comm_ratio" "RO
picc2@grp_ibm500:cbps.a_comm_ratio" "select *
from a_comm_ratio"
4.2.9. 确定replicate 建立
执行picc21 上执行cdr list repl
系统显示如下说明replicate 已建立(但为激活):
REPLICATE STATE CONFLICT FREQUENCY OPTIONS
picc2_a_charge_ratio INACTIVE ignore immediate row,ris,triggers
picc2_a_comm_ratio INACTIVE ignore immediate row,ris,triggers
4.2.10. 启动replicate
执行picc21 上$INformIXDIR/cdr/repstart.sh
脚本内容如下:
cdr start repl picc2_a_charge_ratio
cdr start repl picc2_a_comm_ratio
4.2.11. 确定replicate 已启动
执行picc21 上执行cdr list repl
系统显示如下说明replicate 已激活:
REPLICATE STATE CONFLICT FREQUENCY OPTIONS
picc2_a_charge_ratio ACTIVE ignore immediate row,ris,triggers
picc2_a_comm_ratio ACTIVE ignore immediate row,ris,triggers
4.2.12. 关闭replicate
执行picc21 上$INformIXDIR/cdr/repstop.sh
脚本内容如下:
cdr stop repl picc2_a_charge_ratio
cdr stop repl picc2_a_comm_ratio
4.2.13. 维护CDR ?/@#{J
CDR 配置完成后,系统将按照配置自动完成数据复制功能。根据需要也可以停止CDR 和
重新启动CDR,或者修改CDR 的配置。下面列出几种需要对CDR 进行维护的情况:
1. 使用dbexport 卸载数据库时,需要通过如下命令停止CDR
cdr stop
2. 可以通过如下命令重新启动CDR
cdr start
3. 修改复制时间间隔时,可以通过如下命令修改replicate 的配置
cdr modify repl -a 24:00 repl_name
注:将复制间隔修改为每天24:00 开始复制
可以使用脚本$INformIXDIR/cdr/repmdf.sh 进行成批修改
4. 需要停止某个replicate 时,可以通过如下命令完成
cdr stop repl repl_name
注:可以使用脚本$INformIXDIR/cdr/repstop.sh 停止一批replicate
5. 需要删除某个replicate 时,可以通过如下命令完成
cdr delete repl repl_name
注:可以使用脚本$INformIXDIR/cdr/repdel.sh 进行成批修改
6. 需要删除replicate server 时,可以通过如下命令完成
cdr delete server server_name
4.2.14. 监控CDR 工作情况
1. 可以通过2.3、2.5 、2.7 章节中的命令分别监控replicate server、
participant 和replicate 的状态是否正常。
2. 通过查看/tmp/ats 和/tmp/ris 目录,如有文件存在说明有复制不成功的记录,
通过vi 查看复制不成功的具体原因。
3. 通过查看$INformIXDIR/online.log 文件,判断CDR 运行情况。
4.2.15. CDR 出错处理
一旦有某个表的数据复制不成功, 完成如下步骤恢复该表的数据一致性:
1. Suspend 该表的复制
2. 删除该表在复制库中的数据
3. 从生产库unload 该表数据,再在复制库load 该表数据
4. resum 该表的复制
4.3. CDR 的时间同步
有关ntp(Network time protocol)的配置,必须在CDR 定义之前进行。两台主机必须
通过ntp 做时钟同步,哪台主机做ntp Server 是无所谓的。在跨平台的情况配置有所不同
这里介绍了两种情况:2 台SCO 主机和1 台AIX、1 台SCO
² 2 台主机都是SCO 平台
ntp Server 端:
1) 编辑/etc/ntp.conf(有可能无此文件,可以新建一个文件,其owner 和group 都是bin)
内容如下:
server 127.127.1.0
2) 修改/etc/tcp 文件
在/etc/tcp 文件中查xntpd 行,删除tickadj 一行,下一行的xntpd 后加-g ,
ntp Client 端:
1) 编辑/etc/ntp.conf(有可能无此文件,可以新建一个文件,其owner 和group 都是bin)
内容如下:
peer (ntp Server 的IP 地址)如:peer 11.137.75.131
2) 修改/etc/tcp 文件
在/etc/tcp 文件中查xntpd 行,保留tickadj 一行,下一行的xntpd 后加-g
3)跟踪两台主机ntp 是否同步成功:查/usr/adm 下的syslog
# tail -f syslog
ntp Server 端应有ntp Server 启动的信息
ntp Client 端应每隔5-10 分钟有与ntp Server 握手的信息
² 1 台主机是SCO 平台,1 台主机是AIX 平台
1)server 端必须定义在AIX 平台上且/etc/ntp.conf 文件如下
server 127.127.1.0
fudge 127.127.1.0 refid
注:s
2)xntpd -g (或/etc/rc.tcpid 中加入该行,重启机)
3)查看两台主机是否同步:运行ntpqà readlist
1. 存储过程的使用
公共模块,用存储过程代替函数,可使代码统一。
Client /Server 模式,用存储过程代替函数,减少client 端应用,减少传输量,提高效率。
在SQL 语句中,需要使用存储过程处理复杂的事情。这一点在描述中使用的特别普遍。
2. 存储过程的调用
存储过程有两种调用方式
(1). select getday( “
(2). Execute procedure getday(“
注:exec 为一只有一条记录的表
当存储过程以with resume 返回,返回值超过一列时,只能用第二种调用方式。
这两种方式有一点区别,第二种方式执行的一定是存储过程,第一种方式则不一定。
如下所示:
select mod(7,3) from exec 执行的是系统过程
execute procedure mod(7,4) 执行的是自己定义的存储过程mod。
3. 存储过程的调试
存储过程的调试通常采用两种方法。
(1) 设置debug file ,以trace 方式。
(2) 用return .. with resume 方式调试。
例:1
create procedure getday(t_day date,t_int int ,t_flag char(10)) returning
date;
define i int;
define tt_day date;
DEFINE ESQL,EISAM INT;
DEFINE ETEXT CHAR(80);
Set debug file to “sun.tmp”;
let tt_day="18991231";
let i=0;
if t_flag="year" then
while 1=1
on exception in(-1267) A|)
let i=i+1;
end exception
let tt_day=t_day-i;
let tt_day=tt_day+t_int units year;
trace tt_day;
exit while;
end while;
elif t_flag="month" then
while 1=1
on exception in(-1267)
let i=i+1;
end exception
let tt_day=t_day-i;
let tt_day=tt_day+t_int units month;
trace tt_day;
exit while;
end while;
elif t_flag="day" then
let tt_day=t_day+t_int units day;
else
let tt_day=t_day;
end if;
return tt_day;
end procedure;
例:2
create procedure getday(t_day date,t_int int ,t_flag char(10)) returning
date;
define i int;
define tt_day date;
DEFINE ESQL,EISAM INT;
DEFINE ETEXT CHAR(80);
let tt_day="18991231";
let i=0;
if t_flag="year" then
while 1=1
on exception in(-1267)
let i=i+1;
end exception
let tt_day=t_day-i;
let tt_day=tt_day+t_int units year;
return tt_day with resume;
exit while;
end while;
elif t_flag="month" then
while 1=1
on exception in(-1267)
let i=i+1;
end exception
let tt_day=t_day-i;
let tt_day=tt_day+t_int units month;
return tt_day with resume;
exit while;
end while;
elif t_flag="day" then
let tt_day=t_day+t_int units day;
else
let tt_day=t_day;
end if;
return tt_day;
end procedure;
4. 存储过程中错误的捕获
在4gl 程序中,有whenever error
continue 语句,屏蔽错误,在存储过程中不能使用
whenever error continue,但可以使用on exception 来捕获错误,使存储过程继续执行。
例1
create procedure get_pick_list(p_order_num int) returning int;
define x integer; b
on exception in (-206)
call log_error(-206);
end exception with resume;
select
let x=y;
return x;
end procedure;
例2 : 以下存储过程用以计算时间,标准为向前靠,如“
日加一个月为“
create procedure getday(t_day date,t_int int ,t_flag char(10)) returning
date;
define i int;
define tt_day date;
DEFINE ESQL,EISAM INT;
DEFINE ETEXT CHAR(80);
let tt_day="18991231";
let i=0;
if t_flag="year" then
while 1=1
on exception in(-1267)
let i=i+1;
end exception
let tt_day=t_day-i;
let tt_day=tt_day+t_int units year;
exit while;
end while;
elif t_flag="month" then
while 1=1 No
on exception in(-1267)
let i=i+1;
end exception
let tt_day=t_day-i;
let tt_day=tt_day+t_int units month;
exit while;
end while;
elif t_flag="day" then
let tt_day=t_day+t_int units day;
else
let tt_day=t_day;
end if;
return tt_day;
end procedure;
注:在存储过程中,on exception 的使用有作用域,若使用在循环体内,其作用域为循环体,
退出即退出本次循环。若使用在begin work 与commit work 内,其作用域为begin work 内,退出
即退出该事物体。以下几个实例给予说明:
例1:
create procedure get(t_day date,t_int int )
returning date;
define i int;
define tt_day date;
on exception in(-1267) ----此语句的作用域为整个存储过程
let i=i+1; ----此语句必须为存储过程的第一条语句
end exception with resume; ------注意有with resume
set debug file to "sun.tmp";
let tt_day="18991231";
let i=0;
while 1=1
trace i;
trace tt_day;
let tt_day=t_day-i;
let tt_day=tt_day+t_int units month; ---此处出错后执行while 循
环外的第一条语句,即下面黑色字体的语句。若无with resume 则退出存储过
程。
trace "ok";
trace tt_day;
exit while;
end while;
trace "ok"; ---出错后执行此语句
trace tt_day;
return tt_day;
end procedure;
例2:
create procedure get(t_day date,t_int int )
returning date;
define i int;
define tt_day date;
set debug file to "sun.tmp";
let tt_day="18991231";
let i=0;
while 1=1
on exception in(-1267) ----此语句的作用域为while 循环
let i=i+1; ----必须为while 循环内的第一条语句
end exception; ------注意无with resume
trace i;
trace tt_day;
let tt_day=t_day-i;
let tt_day=tt_day+t_int units month; ---此处出错后执行while 循
环的下一循环,相当于continue while。若有with resume 则执行下面一条语 )
句,即黑色字体的语句。
trace "ok";
trace tt_day;
exit while;
end while;
trace tt_day;
return tt_day;
end procedure;
5. 存储过程的效率
系统中的存储过程尽量放在一个extents 中,最好不要超过8 个extents. ( 注:extents 连
续的存储空间),因此可定期将系统中的所有存储过程重建。
存储过程中使用set optimization low 可提高存储过程的效率,前提是该存储过程中所涉及
的表的结构,字段无任何改动。
更为重要的是存储过程的效率与存储过程中的语句的写法很有关系。有时某一语句换一种写
法,存储过程的效率可得到极大提高。
例如:
create procedure true_rqstart( p_main_cert like rta1.bm_cert,p_kinds like
rta1.kinds ,t_rq_start like rta1.rq_start)
returning date;
define p_rq_start date;
define tt_rq_start date;
define t_bm_min char(20);
define t_bm_max char(20);
define p_bm_cert2 char (20);
let p_rq_start = "
le tt_bm_min = p_kinds[1,3] || p_main_cert[4,7] || "0000000000000";
let t_bm_max = p_kinds[1,3] || p_main_cert[4,7] || "9999999999999";
-- foreach select bm_cert2 into p_bm_cert2 from rta
--bm_cert1=p_main_cert and bm_cert2>=t_bm_min and bm_cert2<=
t_bm_max
-- select rq_start into tt_rq_start from rta1 where bm_cert =
p_bm_cert2;
-- if tt_rq_start > p_rq_start then FST
-- let p_rq_start = tt_rq_start;
-- end if;
--end foreach;
--以上改为以下语句,效率显著提高,从30 分到不到1 秒
--该语句有多种写法,子查询,连表等,但在该存储过程中,以下写法效率最高
foreach select bm_cert2 into p_bm_cert2 from rta
if p_bm_cert2[1,3]=p_kinds then
select rq_start into tt_rq_start from rta1 where bm_cert =
p_bm_cert2;
if tt_rq_start > p_rq_start then
let p_rq_start = tt_rq_start;
end if;
end if;
end foreach;
if p_rq_start = "
if (t_rq_start + 35 units day ) >= today then
return null;
else
return today;
end if;
else
if p_rq_start<>(t_rq_start -1 units year) and (t_rq_start-30 units
SDP day)< (p_rq_start+1 units year) then
let p_rq_start=p_rq_start+1 units year;
return p_rq_start;
else
return null;
end if
end if }
end procedure;
6. 存储过程内SQL 语句执行情况的判断
在4GL 程序中对SQL 语句执行情况的判断可用status, sqlca 等来实现。但在存储过程中,不能直接使用这些全局变量。但可通过dbinfo()来实现。
create procedure num_rows()
returning int;
define num_rows int;
delete from orders where customer_num=104;
let num_rows=dbinfo(“sqlca.sqlerrd[3]”);
return num_rows;