拿到这个问题后,本地重现后,监控sql耗时没有异常,那就着重分析代码了。因为可发量校验的业务逻辑极其复杂,又加上又直接再一个类文件实现该功能,3500+行的代码,加上零星注释,真是让人避之不及。逃避不是办法,还是上工具分析一把。
这次我选用的时VS自带的Performance Profiler,开发环境下极其强大的性能调优工具。针对我们当前案例,我们仅需要跟踪指定服务对应的dll即可,使用步骤如下:
跟踪结束后本案例跟踪到的采样结果如下图:
同时Performance Profiler也给出了问题的建议,如下图:
其中第1、4条大致说明程序I/O消耗大,第一代的GC上存在未及时释放的垃圾占比过高。而根据上图的采样结果,我们可以直接看出是由于再代码中频繁操作DataTable引起的性能瓶颈。走读代码发现的确如此,所有的数量统计都是在代码中循环遍历DataTable进行处理的。而最终的优化策略,就相当于一次大的重构,将所有代码中通过遍历DataTable的计算逻辑全部挪到SQL中去做。由于代码过多,就不再放出。
案例3:客户反馈批量引入1000张订单,耗时40mins左右,且容易中断。
同样,我们还是先尝试本地重写。经测试批量引入101张单据,就耗时5mins左右。下一步打开Sql监控工具也未发现耗时语句。但考虑到是批量导入操作,虽然单个耗时不多,但乘以100这个基数,就明显了。下面我们就使用RedGate的Ants Performance Profiler跟踪一下。
该工具比较直观,可以同时监控代码和SQL执行情况。第一步,New Profiler Session,第二步进行设置,如下图。根据自己的应用程序类别,选择相应的跟踪方式。
针对这个问题,我们跟踪到的调用堆栈和SQL耗时结果如下图:
首先从调用堆栈中的Hit Count,我们可以首先看出它是一个批量过程,因为入口函数仅调用一次;第二个我们可以代码中是循环处理每一个单据,因为Hit Count与我们批量引入的单据数量相符;第三个,突然来了个10201,如果有一定的数字敏感性的话,这次性能问题的原因就被你找到了。这里就不卖关子了,101 x 101 = 10201。
是不是明白了什么,存在循环嵌套循环的情况。我们走读代码确定一下:
好嘛,外层套了一个空循环却什么也没做。修改就很简单了,删除无效外层循环即可。
4.3. 算法优化案例案例4:某全流程跟踪报表超时。
这个报表是用来跟踪所有单据从下单到出库的业务流程数据流转情况。而所有的流程数据都是按照树形结果存储在数据库表中的,类似这样:
图中的流程为:
销售合同-->销售订单-->发货通知单-->销售出库单
为了构造流程图,之前的处理方法是把流程数据取回来,通过代码构造流程图。这也就是性能差的原因。
而针对这种情况,就是考验我们平时经验积累了。对于树形结构的表,我们也是可以通过SQL来进行直接查询的,这就要用到了SQL Server的CTE语法来进行递归查询。关于递归查询,可参考我这篇文章:SQL递归查询知多少。这里就不展开了。
5.总结性能调优是一个循序渐进的过程,不可能一蹴而就,重在平时的点滴积累。关于工具的选择和使用,本文并未展开,也希望读者也不要纠结与此。当你真正想解决一个问题的时候,相信工具的使用是难不住你的。
最后就大致总结下我的调优思路:
posted @