您的位置:首页 > 数据库

20150804客户sqlserver库查询sql执行慢的问题分析

2015-08-09 21:02 435 查看
执行报表反接收操作时检查是否产生关联报表的sql查询。

这条脚本在oracle库都执行正常,执行速度可以控制在0.05s以内。

存在sql查询性能问题的客户情况:

1、操作系统

阿里云 四核、14G内存。数据库服务器分配了10个G的内存。

2、Sql Server设置

3、业务数据:

4、客户出现性能的SQL

SELECT distinct r.FID AS ID,r2.FName AS SourceReport,
r2.FNumber AS SourceReportNumber,
tr.FName_l2 AS TreeName,
o.FName_l2 AS UnitName,
c.FName_l2 AS CurrencyName,
r.FPeriodType AS PeriodType,
r.FYear AS FYear,
r.FPeriod AS Period,
r.FSourceType AS SourceType,
r.FName AS ReportName,
s.FLongNumber AS OrgLongNumber,
r.FCommittedStatus  AS CommittedStatus
FROM T_CSL_CslReport r
INNER JOIN T_Org_Tree tr  ON r.FOrgTreeID = tr.FID
INNER JOIN T_Org_BaseUnit o  ON r.FOrgUnitID = o.FID
INNER JOIN T_BD_Currency c   ON r.FCurrencyID = c.FID
INNER JOIN T_RPT_Template t ON r.FTemplateID = t.FID
INNER JOIN T_CSL_TempletItemList til  ON t.FID = til.FTemplateID
INNER JOIN T_CSL_TempletItemList til2
ON til.FItemNumber = til2.FItemNumber
AND til.FDataElement = til2.FDataElement
AND til.FValueType = til2.FValueType
INNER JOIN T_RPT_Template t2
ON til2.FTemplateID = t2.FID
INNER JOIN T_CSL_CslReport r2
ON t2.FID = r2.FTemplateID AND r.FCurrencyID = r2.FCurrencyID
AND r.FYear = r2.FYear AND r.FPeriod = r2.FPeriod  AND r.FPeriodType = r2.FPeriodType
INNER JOIN T_CSL_RptReceived rec
ON r2.FID = rec.FReportID AND r.FOrgTreeID = rec.FOrgTreeID
INNER JOIN T_Org_Structure s
ON r.FOrgTreeID = s.FTreeID AND r.FOrgUnitID = s.FUnitID
INNER JOIN T_Org_Structure s2
ON rec.FOrgTreeID = s2.FTreeID AND r2.FOrgUnitID = s2.FUnitID
WHERE  r2.FID IN ('Dq8AAABWGky3Euos','Dq8AAABWGnS3Euos','Dq8AAABWGoK3Euos','Dq8AAABWGkK3Euos','Dq8AAABWGqG3Euos')
AND CHARINDEX(s.FLongNumber  + '!', s2.FLongNumber) = 1
AND ((r.FSourceType IN (2,3,4) AND r2.FSourceType IN (1,7))
OR ((r.FSourceType = 2 AND r2.FSourceType = 2) AND (r.FSumCalculateMethod=0 OR r.FSumCalculateMethod=2))
OR (r.FSourceType = 3 AND r2.FSourceType = 3)
OR ((r.FSourceType = 2 AND r2.FSourceType = 3) AND (r.FSumCalculateMethod=1 OR r.FSumCalculateMethod=2)) )


症状:执行完这条查询需要将近半个小时。

sql分析:
1)sql的逻辑:用报表+组织+模板+项目,分别查询出上下级两个试图,进行匹配过滤。

2)性能点:T_CSL_TemplateItemList作为最明细级表,此试图的结果集庞大,特别是查询上级试图时,因为只能通过一些若关键字过滤。

3)优化点:采用子查询方式,缩小中间结果集,提高匹配过滤效率。

优化后sql:

select rpt1.fname, rpt1.fnumber
from (select distinct s.flongnumber, r.fname, r.fnumber
from t_csl_cslreport r
join t_rpt_template tmpl
on r.ftemplateid = tmpl.fid
join t_org_structure s
on r.FCompanyID = s.funitid
join t_csl_rptreceived rec
on rec.freportid = r.fid
and s.ftreeid = rec.forgtreeid
where tmpl.fgroup in
--获取集团模板id
(select distinct temp.fgroup
from t_rpt_template  temp
join t_csl_templetitemlist templist on temp.fid = templist.ftemplateid
where exists (select 1 from tempId tt where templist.fid = tt.fid)
templist.fid in (select lst2.fid
from (select lst.fitemnumber,
lst.fvaluetype,
lst.FDataElement,
lst.fid
from t_csl_templetitemlist lst
where lst.ftemplateid in
(select distinct case  when tmpl.fgrouptemplateid is null then
tmpl.fid
else
tmpl.fgrouptemplateid
end
from t_csl_cslreport r
join t_rpt_template tmpl
on r.ftemplateid = tmpl.fid
where r.fid in ('Dq8AAABLKIm3Euos'))) lst1
join (select lst.fitemnumber,
lst.fvaluetype,
lst.FDataElement,
lst.fid
from t_csl_templetitemlist lst
where lst.ftemplateid in
--找到当前合并范围分配了哪些模板,查t_csl_rptreceived表是因为有一表多报的情况
(select distinct disp.fdispensesrcid
from t_csl_cslreport r
join t_csl_rptreceived rec
on r.fid = rec.freportid
join t_csl_templetdispense disp
on disp.forgboundid = rec.forgtreeid
where r.fid in ('Dq8AAABLKIm3Euos'))) lst2
on lst1.fitemnumber = lst2.fitemnumber
and lst1.fvaluetype = lst2.fvaluetype
and lst1.FDataElement = lst2.FDataElement
and lst1.fid <> lst2.fid )
)) rpt1
join (select s.flongnumber,r.FYear ,r.FPeriod, r.FPeriodType, r.FCurrencyID, r.FSourceType
from t_csl_cslreport r
join t_rpt_template tmpl
on r.ftemplateid = tmpl.fid
join t_org_baseunit unit
on (r.fcompanyid = unit.fid or r.forgunitid = unit.fid)
join t_org_structure s
on unit.fid = s.funitid
join t_csl_rptreceived rec
on rec.freportid = r.fid
and s.ftreeid = rec.forgtreeid
where r.fid in ('Dq8AAABLKIm3Euos')) rpt2
on CHARINDEX(rpt1.FLongNumber + '!', rpt2.FLongNumber) = 1


第一次优化效果:中间结果集明显缩小,已经能把执行时间缩短至两分钟以内。

分析得出,查询项目id的结果集有1000多行数据,于是采用临时表策略,将子查询的id插入临时表中,然后用Exists字句进行过滤。

临时表sql:

insert  into tempId
select lst2.fid
from (select lst.fitemnumber,
lst.fvaluetype,
lst.FDataElement,
lst.fid
from t_csl_templetitemlist lst
where lst.ftemplateid in
(select distinct case  when tmpl.fgrouptemplateid is null then
tmpl.fid
else
tmpl.fgrouptemplateid
end
from t_csl_cslreport r
join t_rpt_template tmpl
on r.ftemplateid = tmpl.fid
where r.fid in ('Dq8AAABWGky3Euos','Dq8AAABWGnS3Euos','Dq8AAABWGoK3Euos','Dq8AAABWGkK3Euos','Dq8AAABWGqG3Euos'))) lst1
join (select lst.fitemnumber,
lst.fvaluetype,
lst.FDataElement,
lst.fid
from t_csl_templetitemlist lst
where lst.ftemplateid in
--找到当前合并范围分配了哪些模板,查t_csl_rptreceived表是因为有一表多报的情况
(select distinct disp.fdispensesrcid
from t_csl_cslreport r
join t_csl_rptreceived rec
on r.fid = rec.freportid
join t_csl_templetdispense disp
on disp.forgboundid = rec.forgtreeid
where r.fid in ('Dq8AAABWGky3Euos','Dq8AAABWGnS3Euos','Dq8AAABWGoK3Euos','Dq8AAABWGkK3Euos','Dq8AAABWGqG3Euos'))) lst2
on lst1.fitemnumber = lst2.fitemnumber
and lst1.fvaluetype = lst2.fvaluetype
and lst1.FDataElement = lst2.FDataElement
and lst1.fid <> lst2.fid


优化后的sql变成:

select  rpt1.fid as id, rpt2.FName AS SourceReport,
rpt2.FNumber AS SourceReportNumber,
rpt1.treeName AS TreeName,
rpt1.unitName AS UnitName,
rpt2.currencyName AS CurrencyName,
--rpt1.FPeriodType AS PeriodType,
--rpt1.FYear AS FYear,
--rpt1.FPeriod AS Period,
rpt1.FSourceType AS SourceType,
rpt1.FName AS ReportName,
rpt1.FLongNumber AS OrgLongNumber,
rpt1.FCommittedStatus  AS CommittedStatus
from (select distinct s.flongnumber, r.fname, r.fnumber, r.fid, t.FName_L2 treeName, u.FName_L2 unitName,
s.FUnitId, r.FSourceType, r.FCommittedStatus, r.FCurrencyID, r.FSumCalculateMethod
from t_csl_cslreport r
join t_rpt_template tmpl
on r.ftemplateid = tmpl.fid
inner join T_ORG_BaseUnit u
on (r.FCompanyID = u.fid or r.FOrgUnitID = u.fid)
inner join t_org_structure s
on u.fid = s.FUnitId
inner join t_org_tree t
on s.FTreeId = t.FID
inner join t_csl_rptreceived rec
on rec.freportid = r.fid
and s.ftreeid = rec.forgtreeid
where tmpl.fgroup in
--获取集团模板id
(select distinct temp.fgroup
from t_rpt_template  temp
join t_csl_templetitemlist templist on temp.fid = templist.ftemplateid
where exists (select 1 from tempId tt where templist.fid = tt.fid)
)
and r.FSourceType in (2,3,4) and r.FYear = 2015 and r.FPeriod = 6 and r.FPeriodType =3
) rpt1
join (select s.flongnumber, r.FNumber, r.FName, c.FName_L2 as currencyName, r.FCurrencyID, r.FSourceType,r.FSumCalculateMethod
from t_csl_cslreport r
join t_rpt_template tmpl
on r.ftemplateid = tmpl.fid
join t_org_baseunit unit
on (r.fcompanyid = unit.fid or r.forgunitid = unit.fid)
join t_org_structure s
on unit.fid = s.funitid
join t_csl_rptreceived rec
on rec.freportid = r.fid
and s.ftreeid = rec.forgtreeid
INNER JOIN T_BD_Currency c   ON r.FCurrencyID = c.FID
where r.fid in ('Dq8AAABWGky3Euos','Dq8AAABWGnS3Euos','Dq8AAABWGoK3Euos','Dq8AAABWGkK3Euos','Dq8AAABWGqG3Euos')) rpt2
on CHARINDEX(rpt1.FLongNumber + '!', rpt2.FLongNumber) = 1
where 1=1 and rpt1.FCurrencyID = rpt2.FCurrencyID
AND ((rpt1.FSourceType IN (2,3,4) AND rpt2.FSourceType IN (1,7))
OR ((rpt1.FSourceType = 2 AND rpt2.FSourceType = 2) AND (rpt1.FSumCalculateMethod=0 OR rpt1.FSumCalculateMethod=2))
OR (rpt1.FSourceType = 3 AND rpt2.FSourceType = 3)
OR ((rpt1.FSourceType = 2 AND rpt2.FSourceType = 3) AND (rpt1.FSumCalculateMethod=1 OR rpt1.FSumCalculateMethod=2)) )
order by rpt1.FSourceType


经测试:完成查询1S之内。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: