场景:
生产上发薪在过账时过长,特别是发薪人数过多时,耗时非常巨大,严重影响发薪效率;
例如:厨房电器过账人数1.3W人,耗时起码4个小时以上;
性能瓶颈在哪?
1.通过测试能判断性能瓶颈在什么地方;
比如:应用层某个地方运算耗时比较多;又或者是某段SQL查询用时过长;数据库插入或删除数据耗时过长;服务器资源竞争激烈;
经过我的测试发现,过账包括两个过程,一个是过账前的数据校验,也是一个耗时的地方,但是这些校验又免不了;
另外一个是校验过后的过账操作,因为过账进行了大量的数据插入和删除操作,同时,所操作的表又是大表,并没有分库分表,所以在对这种大表在进行插入删除时都是比较耗时的;
过账中还有一些数据更新操作,一些查询的SQL也值得优化;可以确定性能瓶颈主要在数据库层面,应用层的瓶颈不算很大;
优化方向:
1.业务层面优化
2.应用层面代码优化
3.数据库层面优化
4.服务器层面优化
业务层面优化
很多应用程序在初期设计阶段并没有充分考虑后期一个业务增长量对系统带来的瓶颈,或者初期设计本身存在一定的不合理性,另外是在长期运维中所做的修改带来的冗余;
所以我们看看在业务层面是否有调整的空间;
比如:经过分析我们发现,过账的时候会将临时表的数据转移到正式表中,然后在删除临时表的数据;这看似正常,但是在取消过账中又将正式表中的数据转移回临时表中;
我们分析后发现,完全可以在过账时不删除临时表数据,这样如果取消过账,也不用在将正式表的数据回写到临时表中;
应用层代码优化
当存在一些计算量比较大的代码块,看看是否有优化的空间;
比如采用多线程的方式进行,提高服务器资源利用率;
分析后发现,各个数据插入操作都相对独立,并没有业务上的关联性,如果单线程方式方式运行,这块耗时巨大,一个等待一个;
所以我采用了多线程的方式进行,每个线程负责独立的数据写入和删除;就不用在出现一个等待一个;
注意点:不要过度使用多线程,要综合考虑服务器资源和数据库资源的情况,使用合理的多线程方式;
比如数据库服务器资源就那么点,更何况整个应用都在共享这份资源,过度占用将导致其他模块响应慢或者系统处于卡死状态;
数据库层面优化
在对过账代码进行分析中发现大量的insert操作,而且是采用一次性的insert;
所以我考虑将这部分insert放入到存储过程中,并且进行批量提交,避免一次性insert占用过多的回滚段;
存储过程采用的是游标循环的方式进行insert,2000条提交一次;性能提升4倍,之前过账1.3W人起码4个小时,优化后资源竞争相对紧张的情况用时1个小时左右,资源充足的情况30分钟左右可以搞定;
资源竞争比较激烈的情况耗时1个小时,甚至多一点,所以我继续寻求优化的方案;
经过了解,存储过程编译后运行在PL/SQL引擎,而SQL语句由SQL引擎进行解析和运行,所以在PL/SQL引擎中的SQL语句会从PL/SQL引擎发送到SQL引擎中运行,这种PL/SQL和SQL引擎之间的切换存在一定的资源消耗,
比如执行100W的数据insert,那么PL/SQL将给SQL引擎发送100W次SQL语句;
经过查询资料发现,存储过程使用forall和bulk collect into替代传统的for循环可以减少PL/SQL引擎和SQL引擎之间切换
forall会将执行的sql语句从PL/SQL引擎一次性发送到SQL引擎,就不用一条一条的去发送了
bulk collect into则是从SQL引擎一次性读取一批数据到PL/SQL引擎中,也就不用在一次一条的执行;
具体可以在网上进行了解;
服务器层面优化
这次我并没有对服务器资源进行调整,但是这个也是要我们关注的一个地方
比如cpu使用情况、IO资源、内存资源等等;