Chinaunix首页 | 论坛 | 博客
  • 博客访问: 302805
  • 博文数量: 94
  • 博客积分: 2220
  • 博客等级: 大尉
  • 技术积分: 975
  • 用 户 组: 普通用户
  • 注册时间: 2004-12-17 21:17
文章分类

全部博文(94)

文章存档

2011年(5)

2010年(11)

2009年(1)

2008年(2)

2006年(1)

2005年(65)

2004年(9)

我的朋友

分类: DB2/Informix

2005-07-11 10:56:45

Informix 高级培训教材(四)

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.32.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 是无所谓的。在跨平台的情况配置有所不同 
这里介绍了两种情况:SCO 主机和AIXSCO
² 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 平台,台主机是AIX 平台 
1)server 
端必须定义在AIX 平台上且/etc/ntp.conf 文件如下
server 127.127.1.0 
fudge 127.127.1.0 refid 
注:s7a time server 所在的主机名 
2)xntpd -g (
/etc/rc.tcpid 中加入该行,重启机
3
)查看两台主机是否同步:运行ntpqà readlist 
1
 存储过程的使用 
公共模块,用存储过程代替函数,可使代码统一。
Client /Server 
模式,用存储过程代替函数,减少client 端应用,减少传输量,提高效率。
SQL 语句中,需要使用存储过程处理复杂的事情。这一点在描述中使用的特别普遍。
2
 存储过程的调用 
存储过程有两种调用方式 
(1). select getday( “1998/1/1”,1,”month”) from exec 
(2). Execute procedure getday(“1998/1/1”,1,”month”) 
注:exec 为一只有一条记录的表 
当存储过程以with resume 返回,返回值超过一列时,只能用第二种调用方式。 
这两种方式有一点区别,第二种方式执行的一定是存储过程,第一种方式则不一定。
如下所示:
select mod(7,3) from exec 
执行的是系统过程
execute procedure mod(7,4) 
执行的是自己定义的存储过程mod
3 存储过程的调试 
存储过程的调试通常采用两种方法。
1 设置debug file ,trace 方式。
2 return .. with resume 方式调试。
例:
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;  
 以下存储过程用以计算时间,标准为向前靠,如1998/1/31”  
日加一个月为1998/2/28” 
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 中,最好不要超过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 = "1899/12/31"
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 rta1f where
--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 分到不到
--
该语句有多种写法,子查询,连表等,但在该存储过程中,以下写法效率最高
foreach select bm_cert2 into p_bm_cert2 from rta1f where bm_cert1=p_main_cert
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 = "1899/12/31" then 
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; 

阅读(1794) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~