大家遇到程序运行慢的问题,会有什么想法?会先做什么呢?
开端
这周遇到了一个程序慢的问题,是中途接手别人的程序的,整个项目我没有参与开发,后面业务反馈效率很低,要优化程序。由于不是自己的代码,遇到了一些坑,持续优化了两个礼拜都没解决问题,最终在讨论的过程中发现问题并完美解决。
第一次优化:首先是优化了部分SQL语句,该加缓存的加了缓存;
第二次优化:再把每次分批执行的数据条数增加;
第三次优化:最好使用了Swoole的协程搞并发(开发环境搞10并发速度飞起,一上线却没有任何效果);
僵持
第四次优化:以为是线上Swoole版本不支持Swoole的协程并发。然后把开发环境Swoole版本改成和线上完全一致,依然没有效果。所以使用了 Redis + PHP多进程执行,先把所有数据存储到 Redis 中,然后 Linux 开启 10个 PHP进程从 Redis 中取数执行。这样开发环境效果显著,一上线效果依然没有。
协商
这时候,时间已经过去了,但是头脑中没有一点思绪,没有找到问题在哪里。
......
然后,我找项目经理,DBA 一起开会沟通,讨论问题可能发生在哪里,DBA 反馈数据库没压力,也没死锁等等,也就是说数据库是正常的不能再正常的。
于是,我们回到程序本身,觉得还是程序里面有问题。DBA 让我给他看看程序逻辑,然后找出每一条执行的 SQL 语句(这里是每一条 SQL,CURD无论大小,无论会不会执行的 SQL 都找出来)。
结论,DBA 检查后发现有两个问题,一是错误使用事务,更新数据库的操作只是在最后面一小撮代码中,然而在程序开始就开启了事务,导致大量的 SELECT 语句是被事务锁定的。并发性能大大降低;二是其中一个更新操作的表字段没有索引,导致全局扫描,占用了逻辑里面 90% 的时间消耗。
结果
最后,优化后,效果显著,效率整整提升了 60 倍。
太棒了!!!
反思
总结这次优化,我能学到什么?
第一:太相信开发员了。开发员是一个8年经验的老手,我是6年经验,我相信他不会在最基本的事情上出错。更何况他已经对程序优化过一段时间了,所以很多地方我忽略跳过了,没有仔细核对。
第二:我盲目自信了。我以己度人,以自己的思维习惯去考虑别人的代码。所以自己绝不会犯错的地方直接忽略,然而别人自己做的最好的地方恰恰是别人做的最大意的地方。
第三:我忽视了细小问题对全局的影响。有句俗活叫一粒老鼠屎坏了一锅羹,我深深体会到了。
总结
这次问题产生的根本是:
代码逻辑中有一个 SQL 在极少情况下会遇到,会全表扫描(120万的表),而这种情况在开发环境是没有的,批量造数据的时候已经干掉了。这也是为什么开发环境效果显著,一上线没有效果的原因。
这其中没有啥难的,如果想到哪就做到哪,很有可能因为主观意识忽略掉某些地方,其实程序优化有一套固定的步骤,按照步骤仔细检查就可以查找到问题。
分享
程序优化的思路:
1.首先优化SQL。打印出每一条SQL,记住是每一条,执行或不执行的都要打印出来(代码里面有的说不定什么场景下就会遇到,所以要全部打印)。仔细检查每个SQL是否使用到索引。
2.优化PHP程序。循环里面的查询改成一次性的批量查询,对查询的数据添加缓存,检查是否有耗时的I/O,单个插入改成批量插入,单个更新改成批量更新。
3.检查数据库锁机制,事务是否会影响并发性能。尽量在最少的逻辑里面加事务。
4.单线程转成多线程,可以使用Swoole或者Linux的多任务实现并发。