关于评审开发人员的sql语句

在平时的工作中,经常会有一些开发人员提出一些数据库相关的一些问题。可能问的最多的就是sql语句了。
按照一个标准的流程,开发提交的sql语句在完成一系列测试之后,在生产部署前,还需要dba来进行审核。如果是紧急的补丁,也一定不要漏了这个问题。
有时候是开发嫌麻烦,要不就是开发嫌dba麻烦,这个review的过程还是很必要的。
在之前的系统迁移中,印象比较深的一个例子就是,开发写了一个Pl/sql,在测试环境中因为没有大量的数据做测试,测试环境美发现任何问题,结果在生产环境部署的时候就直接提交给客户,dba没有做review,等我发现的时,已经是马上要开始系统升级的时候了。当时感觉不妥而且很郁闷,但是如果要调优,时间也来不及了。就硬着头皮开始系统升级。结果在其它部分进展都很顺利,就唯独这个Pl/sql有严重的问题,本来预计半个小时内就要跑完的程序,结果最后硬生生的跑了4个小时,眼看着rollback的时间越来越近了。在这个煎熬的过程中也在同时做性能调优,大半夜的在那调优,背后一大堆人看着,很不自在。
最后发现用几个简单的sql语句就完全可以替代pl/sql,在一个临时的表中进行了测试,结果不到1分钟就执行完了。
更多的调优细节,可以参考: 生产系统pl/sql调优案例  http://blog.itpub.net/23718752/viewspace-1172818/
啰嗦了一大堆,就是想说明脚本复审的重要性,可能开发和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这种语句是错误的,需要纠正一下。
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);

还有因为这个表是一个临时表,所以只限于这个补丁部署中使用,可以采用nologging模式,性能要高很多。
因为表比较大,所以可以考虑加入并行。
所以这个部分的改进如下:
alter session force parallel ddl parallel 8;
create table temp_c_rate_fix_expr_date nologging 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 )
and (last_cyc_expr_date is null );


update的部分其实也可以好好斟酌一下。如果根据第一步创建的临时表,表中数据很少的时候,是可以考虑不用创建索引的。如果数据量大可以考虑创建索引。
最后一部分是删除临时表,可能开发对这个存在一定的误解。在drop 完成之后又使用了commit,这个是不必要的。
drop table temp_c_rate_fix_expr_date;
commit;


可能看似很细小的错误,也可能引起很严重的问题。如果能在脚本上把把关,最后一道防线就是安全的。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/23718752/viewspace-1286287/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/23718752/viewspace-1286287/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
8.用执行计划分析SQL性能      EXPLAIN PLAN是一个很好的分析SQL语句的工具,它可以在不执行SQL的情况下分析语句      通过分析,我们就可以知道ORACLE是怎样连接表,使用什么方式扫描表(索引扫描或全表扫描),以及使用到的索引名称      按照从里到外,从上到下的次序解读分析的结果      EXPLAIN PLAN的分析结果是用缩进的格式排列的,最内部的操作将最先被解读,如果两个操作处于同一层中,带有最小操作号的将首先被执行      目前许多第三方的工具如PLSQL Developer和TOAD等都提供了极其方便的EXPLAIN PLAN工具      PG需要将自己添加的查询SQL文记入log,然后在EXPLAIN PLAN中进行分析,尽量减少全表扫描      ORACLE SQL性能优化系列      1.选择最有效率的表名顺序(只在基于规则的优化器中有效)      ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理      在FROM子句中包含多个表的情况下,必须选择记录条数最少的表作为基础表      当ORACLE处理多个表时,会运用排序及合并的方式连接它们      首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行排序;      然后扫描第二个表(FROM子句中最后第二个表);      最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并      例如:      表 TAB1 16,384 条记录      表 TAB2 5 条记录      选择TAB2作为基础表 (最好的方法)      select count(*) from tab1,tab2 执行时间0.96秒      选择TAB2作为基础表 (不佳的方法)      select count(*) from tab2,tab1 执行时间26.09秒      如果有3个以上的表连接查询,那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表      例如:   EMP表描述了LOCATION表和CATEGORY表的交集   SELECT *   FROM LOCATION L,   CATEGORY C,   EMP E   WHERE E.EMP_NO BETWEEN 1000 AND 2000   AND E.CAT_NO = C.CAT_NO   AND E.LOCN = L.LOCN      将比下列SQL更有效率   SELECT *   FROM EMP E ,   LOCATION L ,   CATEGORY C   WHERE E.CAT_NO = C.CAT_NO   AND E.LOCN = L.LOCN   AND E.EMP_NO BETWEEN 1000 AND 2000      2.WHERE子句中的连接顺序      ORACLE采用自下而上的顺序解析WHERE子句      根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾      例如:   (低效,执行时间156.3秒)   SELECT *   FROM EMP E   WHERE SAL > 50000   AND JOB = 'MANAGER'   AND 25 < (SELECT COUNT(*) FROM EMP WHERE MGR=E.EMPNO);      (高效,执行时间10.6秒)   SELECT *   FROM EMP E   WHERE 25 50000   AND JOB = 'MANAGER';      3.SELECT子句中避免使用'*'      当你想在SELECT子句中列出所有的COLUMN时,使用动态SQL列引用'*'是一个方便的方法,不幸的是,这是一个非常低效的方法      实际上,ORACLE在解析的过程中,会将'*'依次转换成所有的列名      这个工作是通过查询数据字典完成的,这意味着将耗费更多的时间      4.减少访问数据库的次数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值