金蝶云星空性能提升200倍的实战案例
案例背景:案例公司金蝶云星空出入库单据和相关报表查询一年的数据,20分钟都出不来,优化后全部不到1分钟出来,最大的一只程序,原来执行需要3个小时,优化后不到1分钟,性能提升200倍。
摘要:本文不涉及简单的硬件,网络,操作系统,数据库参数和索引优化等稍微靠谱一点的代理商都会的技术,但完整的分析步骤会提供优化文档和性能检查SQL程序 供下载(售价100元),针对所有曾经的新老同事和新老客户 都可免费找作者获取。
分析思路
1 按优化文档分析现状和可优化环节(本文略)
2 找到耗时最多的程序
3 针对这个程序做分析,作用和功能是什么,以及为什么慢
4 针对性优化
执行分析思路
1 按优化文档分析现状和可优化环节
结果:发现90%的部分,已经有人做了优化,但是并没有作用
2 找到耗时最多的程序
结果:发现有一只程序执行了174分钟,大约耗时三小时,并且每4个小时执行一次,导致所有程序受此拖累,出入库单据查询一年的数据,20分钟都出不来
3 针对这个程序做分析,作用和功能是什么,以及为什么慢
下面是优化之前的程序,供参考
CREATE PROCEDURE [dbo].[pro_pur_req_innerText]AS BEGIN PRINT '-----开始--------' DECLARE @FBillNo VARCHAR(200) DECLARE @Fid VARCHAR(200) DECLARE pur_req_order CURSOR FOR ( SELECT DISTINCT a.FID , FBillNo FROM T_PUR_REQUISITION AS a INNER JOIN T_PUR_REQENTRY AS b ON a.FID = b.FID INNER JOIN t_bd_material AS c ON b.FMATERIALID = c.FMATERIALID WHERE CONVERT(VARCHAR(100), a.FCreateDate, 23) > CONVERT(VARCHAR(100), DATEADD(DAY, -10, GETDATE()), 23) AND ISNULL(b.F_BKK_TEXT, '') = '' AND c.FNUMBER LIKE '3%' ) OPEN pur_req_order FETCH NEXT FROM pur_req_order INTO @Fid, @FBillNo WHILE @@FETCH_STATUS = 0 BEGIN PRINT @FBillNo UPDATE A SET A.F_BKK_TEXT = d.Fjx FROM T_PUR_ReqEntry AS A WITH ( NOLOCK ) INNER JOIN ( SELECT DISTINCT b.FID , b.FBILLNO , d.FBILLNO AS reqbill , b.FEntryID , a.FMaterialId , CONCAT(RIGHT(a.Fmodel, PATINDEX('%/%', REVERSE(a.Fmodel))) + ';' + RIGHT(c.Fmodel, PATINDEX('%/%', REVERSE(c.Fmodel))), ';', a.BCJX) Fjx FROM ( SELECT B.FMaterialId , A.FBILLNO , B.FENTRYID , C.FSPECIFICATION fmodel , C.FDESCRIPTION , D.F_BKK_TEXT BCJX --销售订单的料号规格 FROM T_PLN_FORECAST AS a INNER JOIN T_PLN_FORECASTENTRY AS b ON a.FID = b.FID INNER JOIN T_BD_MATERIAL_L AS C ON B.FMaterialId = C.FMaterialId INNER JOIN T_BD_MATERIAL AS D ON B.FMATERIALID = D.FMATERIALID ) AS A INNER JOIN ( SELECT FDEMANDBILLNO , A.FID , a.fbillno , B.FENTRYID , C.FDEMANDBILLENTRYID --关联来源单号 FROM T_PUR_Requisition AS A INNER JOIN T_PUR_ReqEntry AS B ON A.FID = B.FID INNER JOIN T_PUR_ReqEntry_R AS C ON B.FID = C.FID AND B.FENTRYID = C.FENTRYID ) AS B ON a.FBILLNO = b.FDEMANDBILLNO AND a.FENTRYID = b.FDEMANDBILLENTRYID INNER JOIN T_PUR_Requisition AS d WITH ( NOLOCK ) ON b.FID = d.FID AND --关联采购申请单 CONVERT(VARCHAR(100), d.FCreateDate, 23) > CONVERT(VARCHAR(100), DATEADD(DAY, -10, GETDATE()), 23) INNER JOIN ( SELECT DISTINCT a.FParentMaterialId , a.FParentNumber , b.FNUMBER FCHILDNUMBER , b.FSPECIFICATION fmodel --电子表总成 FROM VICBOM AS a INNER JOIN VICBOM AS b ON a.FNUMBER = b.FParentNumber WHERE b.Fname LIKE '%电控总成%' ) AS c ON a.FMaterialId = c.FParentMaterialId ) AS d ON a.FID = d.FID AND a.FEntryID = d.FEntryID WHERE d.reqbill = @FBillNo FETCH NEXT FROM pur_req_order INTO @Fid, @FBillNo END CLOSE pur_req_order DEALLOCATE pur_req_order ENDGO
结论:
2.1 该程序的功能是更新销售订单来源的采购申请单自定义的机型字段
2.2 机型 =销售订单上产品的 规格型号+ BOM展开两层取 电子表总成和 电控总成 的 规格型号
2.3 只更新最近10天的采购申请单,并且按采购申请单号逐个更新
2.4 背景:该程序为前前前任IT总监所写,写完之后还没有优化就离职了,后面的人一直没有解决此问题,也给当地最大的代理商反馈过,金蝶总部也查了,查出了原因,但没有给出优化办法,后面经过多次交接和岁月的流转,连原因也没人知道了
2.5 通过执行计划和代码整体分析,速度慢主要是
2.5.1 通过游标逐个采购申请单号进行循环
2.5.2 每次都要对所有的BOM进行展开,然后再筛选需要的数据
2.5.3 对很多大表都是先join 后筛选,导致各表串联之后 笛卡尔积 变得非常巨大,影响性能
最终优化方法:
1 原有程序整体架构不行,小修小改无法达到大幅改善性能的效果
2 重写原有程序,将游标循环去除,展BOM程序 独立出去,并且先筛选后展开,大幅降低各表串联笛卡尔积的结果
3 实践测试,新程序可以在不到一分钟内执行完成,性能提升200倍。
金蝶云星空ERP性能优化方法实操指南 和 sql server 数据库查看阻塞,耗费IO,CPU资源的语句分析 源代码
https://mbd.pub/o/bread/ZJaXlptu
温馨提示:曾经的同事和新老客户不要拍,可免费找作者获取
总结:文章中提到的查找性能瓶颈的SQL代码,适用于所有基于sql server的应用程序,包含但不限于金蝶,用友ERP等。