2011年5月19日 20:38:23
2011年5月28日 修改
这段时间写了一个PLSQL过程,今天让项目组经理给评审了,受益良多啊,赶紧将金玉良言记录下来:
一段好代码必须让外人在最短的时间表看懂你所写的过程含义。
1、注意编码中命名的规范性。
各种包名,过程名,函数名,变量名都要让人一目了然,从命名中能直接明白含义。
2、在代码中尽量不要使用 count,因为这个影响性能。也许刚开始没什么事,但是随着时间的推移,表的数据量会越来越大,很可能成为以后代码的瓶颈。
若可以则用显式游标代替之。
见如下语句:
改写为:
SELECT 1
FROM itf_n9_sig@resource_link
WHERE trunc(finishdate) = trunc(SYSDATE)
AND step_name = 'itf_n9_gis';
3、在具体过程或函数的begin和end之间,尽量不要出现具体的sql语句。因为sql语句体现了业务逻辑,对于别人来说不容易看懂。也许可以通过游标来替代。
4、尽量不要使用隐式游标。同4,隐式游标直接将sql语句放到begin。。end之间,这样不利于代码的可读性。若可以用显式游标替代之。
5、对于不需要被外部调用的过程,函数,不要在包头中定义,只要在包头中定义了,就是公用了,可以被外部调用。所以尽量将包私有的过程和函数不在包头定义。这样在包体中每个过程的顺序就要按过程间的调用关系进行排列了(需要调用别的过程的过程要在被调用过程后面,因为plsql是从下往上找)。
6、一个问题待确认。如果一个表的数据插入后未提交,是否能直接update?因为我自己在写的过程中就是因为发现了没有提交而导致没法更新,但是今天姜项目经理却给我临时验证在sql中是可以的。也许是自己理解错了,当时的那个问题并不是因为insert数据没有提交而导致代码错误。
经过再次验证结论如下:
原过程如下:
v_sql VARCHAR2(4000);
BEGIN
pkg_public.P_writeProgramLog(r_parameter.g3e_fno || '增量表开始更新');
v_sql := pkg_public.f_replaceString('insert /*+append*/ into {1} ({2}) select {3} from {4} d where not exists(select 1 from {1} where id=d.id)',
str_array(r_parameter.G3E_ZYTB_TABLE,
r_parameter.G3E_ZYTB_COLUMNS,
r_parameter.G3E_SOURSE_COLUMNS,
r_parameter.G3E_SOURSE_TABLE));
EXECUTE IMMEDIATE v_sql;--(1)
COMMIT; --该处的commit若省略,则无法执行后面的update语句。
v_sql := REPLACE('update {1} a set a.g3e_fid=g3e_fid_seq.nextval where a.processtype=''INSERT'' and a.g3e_fid is null /*and a.edite >=trunc(sysdate)*/',
'{'||1||'}',
r_parameter.G3E_ZYTB_TABLE);
EXECUTE IMMEDIATE v_sql;
v_sql := REPLACE('update {1} a set a.g3e_fid = (select g3e_fid from {1} where a.sourceid = sourceid and processtype = ''INSERT'') where a.processtype = ''UPDATE'' and a.g3e_fid is null /*and a.edite >= trunc(sysdate)*/',
'{'||1||'}',
r_parameter.G3E_ZYTB_TABLE);
EXECUTE IMMEDIATE v_sql;
v_sql := REPLACE('update {1} a set a.g3e_fid = (select g3e_fid from {1} where a.sourceid = sourceid and processtype = ''INSERT'') where a.processtype = ''DELETE'' and a.g3e_fid is null /*and a.edite >= trunc(sysdate)*/',
'{'||1||'}',
r_parameter.G3E_ZYTB_TABLE);
EXECUTE IMMEDIATE v_sql;
COMMIT;
pkg_public.P_writeProgramLog(r_parameter.g3e_fno || '增量表更新成功');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
pkg_public.P_writeProgramLog((sqlerrm) || substr(v_sql, 1, 2000) ||
r_parameter.g3e_fno || '增量表更新出错');
END;
如果将以上代码的(1)insert sql语句改成静态的,那么该过程中在对表itf_zytb_exch之后就不用先commit可以直接进行后面的update操作。
insert 语句改成静态的如下所示:
INTO itf_zytb_exch
(id,sourceid,station_id,processtype,prj_no,edite,super_station_name,station_no,china_name_ab,district_name,
childregion_name,union_station_no,union_china_name,region2_name,building_kind_name,mnt_spec_name,location,
type_name,grade_name,isstation,linkman,phone,builddate,building_wiring,including_range,building_fghs,
buliding_xqsx,building_jrsx,busi_permit_range,open_time,china_name_full,building_up_point,building_up_rme,
building_up_method,building_pm,building_rme,open_no,submit_man,x,y,station_type_name)
SELECT id,sourceid,station_id,processtype,prj_no,edite,super_station_name,station_no,china_name_ab,district_name,
childregion_name,union_station_no,union_china_name,region2_name,building_kind_name,mnt_spec_name,location,
type_name,grade_name,isstation,linkman,phone,builddate,building_wiring,including_range,building_fghs,
buliding_xqsx,building_jrsx,busi_permit_range,open_time,china_name_full,building_up_point,building_up_rme,
building_up_method,building_pm,building_rme,open_no,submit_man,pos_x,pos_y,station_type_name
FROM itf_n9_exch d
WHERE NOT EXISTS (SELECT 1 FROM itf_zytb_exch WHERE id = d.id)';
因此,验证的结果初步认为,对于insert append语句,如是该语句为动态的则必须在insert后执行commit方可继续对该表执行读写操作。
7、子过程。如果一个过程只被调用一次,那么将该过程作为调用此过程的子过程。
8、写过程要注意事务,什么情况下执行提交(如果出现ddl语句,默认的提交会将之前没提交的数据都提交,因此注意用自治事务的方式处理ddl语句)
9、尽可能考虑程序中可能出现的各种例外。