在平时的工作中,经常会有一些开发人员提出一些数据库相关的一些问题。可能问的最多的就是sql语句了。
按照一个标准的流程,开发提交的sql语句在完成一系列测试之后,在生产部署前,还需要dba来进行审核。如果是紧急的补丁,也一定不要漏了这个问题。
有时候是开发嫌麻烦,要不就是开发嫌dba麻烦,这个review的过程还是很必要的。
在之前的系统迁移中,印象比较深的一个例子就是,开发写了一个Pl/sql,在测试环境中因为没有大量的数据做测试,测试环境美发现任何问题,结果在生产环境部署的时候就直接提交给客户,dba没有做review,等我发现的时,已经是马上要开始系统升级的时候了。当时感觉不妥而且很郁闷,但是如果要调优,时间也来不及了。就硬着头皮开始系统升级。结果在其它部分进展都很顺利,就唯独这个Pl/sql有严重的问题,本来预计半个小时内就要跑完的程序,结果最后硬生生的跑了4个小时,眼看着rollback的时间越来越近了。在这个煎熬的过程中也在同时做性能调优,大半夜的在那调优,背后一大堆人看着,很不自在。
最后发现用几个简单的sql语句就完全可以替代pl/sql,在一个临时的表中进行了测试,结果不到1分钟就执行完了。
啰嗦了一大堆,就是想说明脚本复审的重要性,可能开发和dba进行脚本审查的角度不一样,开发侧重于业务,dba侧重要系统。可能结合起来效果就好一些。
举一个例子。
今天开发找我复审一些一个补丁脚本,需要修复一些数据,他们的思路就是创建一个临时的表(不是临时表),然后给临时表加个索引,和一个大表进行关联update,update结束后,把这个临时的表给删除。
create table temp_c_rate_fix_expr_date as
select rc_rate_seq_no,expiration_date,last_cyc_expr_date,(SELECT End_Date FROM Cycle_Control WHERE Cycle_Control.Cycle_Code=c_rates.Cycle_Code AND Trunc(expiration_date,'dd') BETWEEN Start_Date AND End_Date) shoudate,
service_receiver_id
FROM C_RATES WHERE sys_creation_date = to_date('20140818','yyyymmdd') and (expiration_date is not null or expiration_date != null)
and (last_cyc_expr_date = null or last_cyc_expr_date is null);
create unique index temp_c_rate_1ux on temp_c_rate_fix_expr_date (rc_rate_seq_no,service_receiver_id) nologging ;
update ( select rc.last_cyc_expr_date OLD, tmp.shoudate NEW, rc.dl_update_stamp DL
from c_rates rc, temp_c_rate_fix_expr_date tmp
where tmp.rc_rate_seq_no = rc.rc_rate_seq_no and tmp.service_receiver_id = rc.service_receiver_id)
set OLD = NEW,
DL = :patch_id ;
COMMIT ;
drop table temp_c_rate_fix_expr_date;
commit;
这个思路我不反对,其实也是蛮高效的,而且易于控制。
但是细细查看脚本,还是发现了一些问题
首先是关于null的部分,开发人员不是很理解null的用途,其实expiration_date != null这种语句是错误的,需要纠正一下。
还有因为这个表是一个临时表,所以只限于这个补丁部署中使用,可以采用nologging模式,性能要高很多。
因为表比较大,所以可以考虑加入并行。
所以这个部分的改进如下:
alter session force parallel ddl parallel 8;
create table temp_c_rate_fix_expr_date nologging as
FROM C_RATES WHERE sys_creation_date = to_date('20140818','yyyymmdd') and (expiration_date is not null )
and (last_cyc_expr_date is null );
update的部分其实也可以好好斟酌一下。如果根据第一步创建的临时表,表中数据很少的时候,是可以考虑不用创建索引的。如果数据量大可以考虑创建索引。
最后一部分是删除临时表,可能开发对这个存在一定的误解。在drop 完成之后又使用了commit,这个是不必要的。
可能看似很细小的错误,也可能引起很严重的问题。如果能在脚本上把把关,最后一道防线就是安全的。