用友股份-LE服务支持部技术方案--《结帐效率问题解决案例》建立日期:2013-04-01修改日期:xxxx-xx-xx文档属性:客户文控编号:LE-DY-JS-2013-00412/13文档控制创建记录审阅人姓名所属部门职位审阅签字发布人姓名所属部门发布时间日期作者所属部门邮件地址版本2013-04-01魏享林V1.03目录结帐效率问题解决案例.......................................................................................................4一.系统环境..................................................................................................................4二.问题描述................................................................................................................4三.检查分析................................................................................................................4四.解决方法..............................................................................................................134结帐效率问题解决案例一.系统环境NC版本:NC502:数据库:Oracle10G二.问题描述结帐突然变得特别慢,要1个小时左右。有一条SQL运行特别慢三.检查分析1.找到那条慢的SQL,分析其执行计划SELECTDISTINCT(voucher.pk_voucher),voucher.pk_glorgbook,voucher.prepareddate,voucher.NO,voucher.pk_vouchertype,voucher.pk_prepared,voucher.totalcredit,voucher.totaldebit,5voucher.explanationFROMgl_vouchervoucherINNERJOINgl_detaildetailONvoucher.pk_voucher=detail.pk_voucherANDvoucher.pk_glorgbook='0001AA100000000008RC'ANDdetail.pk_glorgbook='0001AA100000000008RC'INNERJOINbd_accsubjsubjONdetail.pk_accsubj=subj.pk_accsubjINNERJOINgl_reconcilesubjrecsubjON(recsubj.isonlyinnercust='Y'and(subj.subjcodeLIKETRIM(recsubj.anothersubjcode)||'%'ORsubj.subjcodeLIKETRIM(recsubj.onesubjcode)||'%')ANDsubj.pk_glorgbook='0001AA100000000008RC')INNERJOINbd_cumandocmanONdetail.pk_glorgbook='0001AA100000000008RC'ANDman.pk_corp='1002'INNERJOINgl_freevaluefreeONdetail.assid=free.freevalueidINNERJOINbd_cubasdocbasONfree.checkvalue=bas.pk_cubasdocANDbas.pk_cubasdoc=man.pk_cubasdocANDfree.checktypeIN('00010000000000000071',6'00010000000000000072','00010000000000000073')WHEREvoucher.pk_glorgbook='0001AA100000000008RC'ANDdetail.pk_glorgbook='0001AA100000000008RC'AND((man.cooperateflag=recsubj.isonlyinnercustANDrecsubj.isonlyinnercust='Y'ANDbas.pk_corp1ISNOTNULLANDbas.custprop<>0ANDEXISTS(SELECT1FROMbd_glorgorgINNERJOINbd_glorgbookotherONother.pk_glorg=org.pk_glorgINNERJOINbd_glorgbookSELFONSELF.pk_glorgbook='0001AA100000000008RC'WHEREorg.pk_entityorg=bas.pk_corp1AND(recsubj.reconcilebookISNULLANDother.TYPE=0)OR(recsubj.reconcilebookISNOTNULLANDSELF.prop=recsubj.reconcilebookANDother.prop=recsubj.reconcilebook))))ANDman.pk_corp='1002'AND((voucher.prepareddate>=recsubj.startdateANDrecsubj.startdateISNOTNULL)OR(recsubj.startdateISNULL))andvoucher.pk_glorgbookin('0001AA100000000008RC')7andvoucher.free1='08'andvoucher.year='2010'andvoucher.pk_sourcepkisnullandvoucher.dr=0andvoucher.discardflag='N'andvoucher.voucherkind<>2andvoucher.errmessageisnullanddetail.busireconnoisnullandnotexists(selectpk_detailselffromgl_reconoccursubwheredetail.pk_detail=gl_reconoccursub.pk_detailself)andnotexists(selectpk_detailotherfromgl_reconoccursubwheredetail.pk_detail=gl_reconoccursub.pk_detailother)orderbyvoucher.PK_glorgbook执行计划如下:8总的cost只有511,而执行要近1小时,说明估计的cost肯定不正确,执行计划肯定也不是最优的计划。2.执行计划中最先访问的表是bd_cubasdoc,认为该表符合条件的记录只有一条,导致其他几张表同该表关联时,都走nestloop,并认为返回的记录只有一条。3.找到bd_cubasdoc表的过滤条件:bas.pk_corp1ISNOTNULLAND9bas.custprop<>0,按这个过滤条件直接查询bd_cubasdoc表,发现返回的记录条数为100.4.分别按bas.pk_corp1ISNOTNULL和bas.custprop<>0这两个条件查询bd_cubasdoc表中记录,发现这两个条件过滤出的记录是相同的。5.确认是Oracle在两列强相关时,无法判断出这两列之间的紧耦合关系,10G下不能收集列之间的统计信息。6.在bd_cubasdoc表的pk_corp1和custprop上建立一个索引,再收集该表索引列统计信息,发现在预估行数时还是预估为1,说明列上的统计信息是记录在列上,同索引无关。7.修改SQL语句,加入Hint,直接提示bd_cubasdoc表返回100行,发现SQL可以在30s左右完成,SQL如下:SELECT/*+cardinality(bas,100)*/DISTINCT(voucher.pk_voucher),其执行计划如下:108.SQL中加Hint可以作为一种解决方案,但是感觉不太理想,询问产品支持及开发得知,pk_corp1不为空时,custprop肯定不等于0,所以该条SQL中,custprop<>0这条条件去掉,不影响查询结果正确性。修改后的SQL执行计划如下:11发现对bd_cubasdoc表的行数预估还是错了,出错原因是:系统认为bas.pk_corp1isnotnull这个条件写了两遍,查找SQL语句,没有发现别的pk_corp1isnotnull的条件,但发现有在pk_corp1上的表关联条件:WHEREorg.pk_entityorg=bas.pk_corp112这个关联条件已经默认bas.pk_corp1不能为空,这就是为什么过滤条件中有两个bas.pk_corp1isnotnull的原因。这说明,SQL中的bas.pk_corp1isnotnull和bas.custprop<>0这两个条件都没有必要,去掉SQL中这两个筛选条件,执行计划如下:可以看出,同加cardinality提示的总cost很接近,这条SQL也能在30秒左右执行出来。9.让开发修改代码,用户打上补丁后,结帐在40秒左右完成。13四.解决方法修改代码,去掉SQL中的bas.pk_corp1isnotnullandbas.custprop<>0条件,提供补丁。补丁编号为:NC_FI_GL-NC5.6-Special-2013049-204456089