一次sql脚本的优化
说明
做了一次sql脚本的优化。结果还是比较满意的。执行时间从2分半钟降到了3秒左右。
从过程中看,其实得到这个结果并不是因为优化做得多么出色,而是因为以前的脚本写得太烂。换句话说,这一次的优化并不是把一个正常的脚本修改得很出色,而是把一个糟糕的脚本修改得比较正常。
不过我比较知足。一方面用户接受了这个结果。另一方面,那个糟糕的脚本本来也是我写的……
分析
原先的脚本之所以这么糟糕,主要原因是子查询太多。几乎每一个字段都有一个子查询语句。而且每个子查询都是先获取一个全集,然后从全集中去查所需要的数据。然而实际上,子查询只需要以一个子集为依据。
优化策略
所以这次优化的策略是:先把最终需要的字段分成三组,对应的把全集拆分成三个子集。先从子集里查出所需的每组字段,然后再对三组字段进行连接。从子集里查出各组字段也不再使用子查询的方式,而是尽可能的使用连接。
其实就只做了这么一点事情。简单地说就是去掉了不必要的重复操作,以及缩小查询的起始范围。另外,作为个人的一点收获,对sql的一些语法也更熟悉了些。
贴一小段代码吧。觉得前后一样烂的兄弟们请轻拍,IT何苦为难IT。
优化前
select u.userCode,
u.userName,
u.comCode,
(select o.comcname
from t_atip_organization o
where o.comcode = u.comcode) as comName,
ym.sjmc,
-- 主審項目數
(select count(distinct p.projectapprovalcode)
from t_atip_projectapproval p, t_atip_prostatustrack ps
where p.chiefaudit = u.usercode
and p.projectlevel = '1'
and p.projectyear = substr(ym.sjmc, 0, 4)
and ps.projectapprovalcode = p.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and ym.sjmc =
(select distinct to_char(max(updatedate), 'yyyy-MM')
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
substr(p.projectapprovalcode, 0, 21))) as chiefAuditCount,
-- 主審項目中發現問題總數
(select count(distinct(prob.seqno))
from t_atip_problem prob,
t_atip_projectapproval proj,
t_atip_prostatustrack ps
where prob.programcode = proj.projectapprovalcode
and proj.chiefaudit = u.usercode
and prob.isrecall = '1'
and proj.projectyear = substr(ym.sjmc, 0, 4)
and ps.projectapprovalcode = proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and ym.sjmc =
(select distinct to_char(max(updatedate), 'yyyy-MM')
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
substr(proj.projectapprovalcode, 0, 21))) as chiefProbelCount,
-- 主審項目中發現的重大問題總數
(select count(distinct(prob.seqno))
from t_atip_problem prob,
t_atip_projectapproval proj,
t_atip_prostatustrack ps
where prob.programcode = proj.projectapprovalcode
and prob.problemlevel in ('13', '14')
and proj.chiefaudit = u.usercode
and prob.isrecall = '1'
and proj.projectyear = substr(ym.sjmc, 0, 4)
and ps.projectapprovalcode = proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and ym.sjmc =
(select distinct to_char(max(updatedate), 'yyyy-MM')
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
substr(proj.projectapprovalcode, 0, 21))) as chiefMainProbCount,
-- 作為主審的被評分項目數
(select count(distinct p.projectapprovalcode)
from t_atip_projectevaluation eval,
t_atip_projectapproval p,
t_atip_prostatustrack ps
where (eval.projectcode = p.projectapprovalcode or
p.projectapprovalcode =
substr(eval.projectcode, 0, length(eval.projectcode) - 3))
and p.chiefaudit = u.usercode
and eval.usercode = u.usercode
and p.projectlevel = '1'
and p.projectyear = substr(ym.sjmc, 0, 4)
and ps.projectapprovalcode = p.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and ym.sjmc =
(select distinct to_char(max(updatedate), 'yyyy-MM')
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
substr(p.projectapprovalcode, 0, 21))) as chiefGradedProjectCount,
--作為主審被評分的總分
/*(select round(nvl(avg(sum(eval.score)), 0), 2) as avgscore
from t_atip_projectevaluation eval,
t_atip_projectapproval p,
t_atip_prostatustrack ps
where (eval.projectcode = p.projectapprovalcode or
p.projectapprovalcode =
substr(eval.projectcode, 0, length(eval.projectcode) - 3))
and p.chiefaudit = u.usercode
and eval.usercode = u.usercode
and p.projectlevel = '1'
and p.projectyear = substr(ym.sjmc, 0, 4)
and ps.projectapprovalcode = p.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and ym.sjmc =
(select distinct to_char(max(updatedate), 'yyyy-MM')
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
substr(p.projectapprovalcode, 0, 21))
group by eval.projectcode, eval.evaluationusercode)*/
(SELECT SUM(ma.avgtotalscore)
FROM (SELECT m.projectcode,
m.usercode,
AVG(projtotalscore) avgtotalscore
FROM (select substr(eval.projectcode, 0, 21) projectcode,
eval.usercode,
eval.evaluationusercode,
sum(nvl(eval.score,0)) as projtotalscore
from t_atip_projectevaluation eval
group by substr(eval.projectcode, 0, 21),
eval.evaluationusercode,
eval.usercode) m
GROUP BY m.projectcode, m.usercode) ma,
t_atip_projectapproval p,
t_atip_prostatustrack ps
WHERE ma.projectcode = p.projectapprovalcode
AND p.projectlevel = '1'
AND p.projectyear = substr(ym.sjmc, 0, 4)
AND ma.usercode = p.chiefaudit
AND p.chiefaudit = u.usercode
and ps.projectapprovalcode = p.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and ym.sjmc =
(select distinct to_char(max(updatedate), 'yyyy-MM')
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
substr(p.projectapprovalcode, 0, 21))
GROUP BY ma.usercode)
as chiefTotalGrade,
-- 作為主審被質檢打分的項目數
(select count(distinct qual.projectcode)
from t_atip_qualitytype qual,
t_atip_projectapproval proj,
t_atip_prostatustrack ps
where qual.projectcode = proj.projectapprovalcode
and proj.chiefaudit = u.usercode
and proj.projectlevel = '1'
and proj.projectyear = substr(ym.sjmc, 0, 4)
and ps.projectapprovalcode = proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and ym.sjmc =
(select distinct to_char(max(updatedate), 'yyyy-MM')
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
substr(proj.projectapprovalcode, 0, 21))) as chiefQualifiedProjectCount,
--作為主審被質檢打分的總分
(select nvl(sum(qual.score), 0)
from t_atip_qualitytype qual,
t_atip_projectapproval proj,
t_atip_prostatustrack ps
where qual.projectcode = proj.projectapprovalcode
and proj.chiefaudit = u.usercode
and proj.projectlevel = '1'
and proj.projectyear = substr(ym.sjmc, 0, 4)
and ps.projectapprovalcode = proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and ym.sjmc =
(select distinct to_char(max(updatedate), 'yyyy-MM')
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
substr(proj.projectapprovalcode, 0, 21))) as chiefTotalQualified
from t_atip_user u,
(select to_char(add_months(date '2003-12-01', 1 * rownum), 'yyyy-MM') sjmc
from dual
where 1 = 1
connect by rownum <
(select months_between(trunc(sysdate, 'mm'),
trunc(date '2003-12-01', 'mm'))
from dual) + 1) ym
where u.validstatus = '1'
and u.istemporary = '0'
优化后
select USERCODE,
COMCODE,
SJMC,
sum(CHIEFAUDITCOUNT) as CHIEFAUDITCOUNT,
sum(CHIEFEVECTIONCOUNT) as CHIEFEVECTIONCOUNT,
sum(CHIEFTOTALQUALIFIED) as CHIEFTOTALQUALIFIED,
sum(CHIEFQUALIFIEDPROJECTCOUNT) as CHIEFQUALIFIEDPROJECTCOUNT,
sum(CHIEFTOTALGRADE) as CHIEFTOTALGRADE,
sum(CHIEFGRADEDPROJECTCOUNT) as CHIEFGRADEDPROJECTCOUNT,
sum(CHIEFMAINPROBCOUNT) as CHIEFMAINPROBCOUNT,
sum(CHIEFPROBELCOUNT) as CHIEFPROBELCOUNT
from (
-- 只計算項目數和出差天數,其它全部置為0
select u.userCode,
u.comCode,
(to_char(ps.updatedate, 'yyyy-MM')) as sjmc,
-- 主審項目數
count(proj.projectapprovalcode) as chiefAuditCount,
-- 主審出差天數
sum(proj.totalday) as chiefEvectionCount,
-- 作為主審被質檢打分的總分,暫時繞過
0 as chiefTotalQualified,
-- 作為主審被質檢打分的項目數
0 as chiefQualifiedProjectCount,
-- 主審被評分項目總分,暫時繞過吧……
0 as chiefTotalGrade,
-- 主審被評分項目數
0 as chiefGradedProjectCount,
-- 主審項目中發現重大問題總數
0 as chiefMainProbCount,
--主審項目中發現問題總數
0 as chiefProbelCount
from t_atip_user u,
t_atip_prostatustrack ps,
t_atip_projectapproval proj
where ps.projectapprovalcode = proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and proj.projectyear = to_char(ps.updatedate, 'yyyy')
and proj.chiefaudit = u.usercode
and proj.projectlevel = '1'
and u.validstatus = '1'
and u.istemporary = '0'
group by u.usercode, u.comcode, to_char(ps.updatedate, 'yyyy-MM')
union all
-- 只計算主審項目中發現重大問題總數和發現問題總數,其它全部置為0
select u.userCode,
u.comCode,
(to_char(ps.updatedate, 'yyyy-MM')) as sjmc,
-- 主審項目數
0 as chiefAuditCount,
-- 主審出差天數
0 as chiefEvectionCount,
-- 作為主審被質檢打分的總分,暫時繞過
0 as chiefTotalQualified,
-- 作為主審被質檢打分的項目數
0 as chiefQualifiedProjectCount,
-- 主審被評分項目總分,暫時繞過吧……
0 as chiefTotalGrade,
-- 主審被評分項目數
0 as chiefGradedProjectCount,
-- 主審項目中發現重大問題總數
count(distinct mainprob.seqno) as chiefMainProbCount,
--主審項目中發現問題總數
count(distinct prob.seqno) as chiefProbelCount
from t_atip_user u,
t_atip_prostatustrack ps,
t_atip_projectapproval proj
left join t_atip_problem prob on prob.programcode =
proj.projectapprovalcode
and prob.isrecall = '1'
left join t_atip_problem mainprob on mainprob.seqno = prob.seqno
and mainprob.problemlevel in
('13', '14')
where ps.projectapprovalcode = proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and proj.projectyear = to_char(ps.updatedate, 'yyyy')
and proj.chiefaudit = u.usercode
and proj.projectlevel = '1'
and u.validstatus = '1'
and u.istemporary = '0'
group by u.usercode, u.comcode, to_char(ps.updatedate, 'yyyy-MM')
union all
-- 只計算主審被評分項目總分和主審被評分項目數,其它全部置為0
-- 主審被評分總分的計算過程比較複雜,這裡採用的仍是優化之前的語句
select USERCODE,
COMCODE,
SJMC,
CHIEFAUDITCOUNT,
CHIEFEVECTIONCOUNT,
CHIEFTOTALQUALIFIED,
CHIEFQUALIFIEDPROJECTCOUNT,
round(nvl(sum(CHIEFTOTALGRADE), 0), 2) as CHIEFTOTALGRADE,
nvl(sum(CHIEFGRADEDPROJECTCOUNT), 0) as CHIEFGRADEDPROJECTCOUNT,
CHIEFMAINPROBCOUNT,
CHIEFPROBELCOUNT
from (select u.userCode,
u.userName,
u.comCode,
o.comcname as comName,
(to_char(ps.updatedate, 'yyyy-MM')) as sjmc,
-- 主審出差天數
0 as chiefEvectionCount,
-- 作為主審被質檢打分的總分
0 as chiefTotalQualified,
-- 作為主審被質檢打分的項目數
0 as chiefQualifiedProjectCount,
-- 主審被評分項目總分
(SELECT SUM(ma.avgtotalscore)
FROM (SELECT m.projectcode,
m.usercode,
AVG(projtotalscore) avgtotalscore
FROM (select substr(eval.projectcode, 0, 21) projectcode,
eval.usercode,
eval.evaluationusercode,
sum(nvl(eval.score, 0)) as projtotalscore
from t_atip_projectevaluation eval
group by substr(eval.projectcode, 0, 21),
eval.evaluationusercode,
eval.usercode) m
GROUP BY m.projectcode, m.usercode) ma
WHERE ma.projectcode = proj.projectapprovalcode
AND proj.projectlevel = '1'
AND proj.projectyear =
to_char(ps.updatedate, 'yyyy')
AND ma.usercode = proj.chiefaudit
AND proj.chiefaudit = u.usercode
and ps.projectapprovalcode =
proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
ps.projectapprovalcode)
GROUP BY ma.usercode) as chiefTotalGrade,
-- 主審被評分項目數
(select sum(count(distinct eval.projectcode))
from t_atip_projectevaluation eval
where eval.projectcode = proj.projectapprovalcode
and eval.usercode = proj.chiefaudit
group by eval.projectcode) as chiefGradedProjectCount,
-- 主審項目中發現重大問題總數
0 as chiefMainProbCount,
--主審項目中發現問題總數
0 as chiefProbelCount,
-- 主審項目數
0 as chiefAuditCount
from t_atip_user u,
t_atip_prostatustrack ps,
t_atip_organization o,
t_atip_projectapproval proj
where o.comcode = u.comcode
and ps.projectapprovalcode = proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno = (select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode =
ps.projectapprovalcode)
and proj.projectyear = to_char(ps.updatedate, 'yyyy')
and proj.chiefaudit = u.usercode
and proj.projectlevel = '1')
group by USERCODE, COMCODE, SJMC
union all
-- 只計算質檢項目總數和質檢總分,其它全部置為0
select u.userCode,
u.comCode,
(to_char(ps.updatedate, 'yyyy-MM')) as sjmc,
-- 主審項目數
0 as chiefAuditCount,
-- 主審出差天數
0 as chiefEvectionCount,
-- 作為主審被質檢打分的總分
round(nvl(sum(qual.score), 0), 2) as chiefTotalQualified,
-- 作為主審被質檢打分的項目數
count(distinct qual.projectcode) as chiefQualifiedProjectCount,
-- 主審被評分項目總分
0 as chiefTotalGrade,
-- 主審被評分項目數
0 as chiefGradedProjectCount,
-- 主審項目中發現重大問題總數
0 as chiefMainProbCount,
--主審項目中發現問題總數
0 as chiefProbelCount
from t_atip_user u,
t_atip_prostatustrack ps,
t_atip_projectapproval proj
left join t_atip_qualitytype qual on qual.projectcode =
proj.projectapprovalcode
where ps.projectapprovalcode = proj.projectapprovalcode
and ps.projectstutas > '04'
and ps.seqno =
(select max(seqno)
from t_atip_prostatustrack tempps
where tempps.projectapprovalcode = ps.projectapprovalcode)
and proj.projectyear = to_char(ps.updatedate, 'yyyy')
and proj.chiefaudit = u.usercode
and proj.projectlevel = '1'
and u.validstatus = '1'
and u.istemporary = '0'
group by u.usercode, u.comcode, to_char(ps.updatedate, 'yyyy-MM'))
group by USERCODE, COMCODE, SJMC