前言
今天测试小哥屁颠屁颠的找过来说查询会员信息这块访问速度很慢,之前没有问题,现在输入信息之后根本就没有反应.要等好好长时间才行.另外点击其他页面都是显示网络连接异常,感觉整个系统都会崩溃了。每次测试找过来都当做是对自己的一次技术提升,尤其是对和业务逻辑关联不高的问题更感兴趣,哈哈!现在把问题分析以及处理过程简单记录一下,希望对有相同线上问题的同学能提供一些解决思路.
问题分析
处理问题的第一步就是场景复现,本地打开网站看了一下确实如此.简单描述一下问题场景:这里面有一个根据会员姓名或是手机号或是卡号模糊查询会员信息的接口,选中用户简要信息之后会显示用户的详情信息,每次输入一个字符之后会调用接口进行查询,有点类似于百度中输入搜索词之后会显示相关联的搜索词.业务截图如下:
以下截图为输入多次字符时的调用接口查询情况,由于已经对服务端存在问题做过处理,所以显示的状态都是200,修改之前都是等待状态:pending.
分析之后主要存在两个问题:
1.接口调用过于频繁
每次输入一个字符都进行接口调用,如果手速快的话对服务器冲击得多大.看过百度或是谷歌的关联词查询,人家那么高的服务器配置都不敢输入一个字符接着去调用一次服务端,中间需要间隔一定的时间,具体的间隔调用时间可以根据数据量进行调整,以不影响用户体验为要求.这种处理方式在前端叫做节流处理,简单意思就是说在指定的时间段内不限制用户数输入的字符数,能输入几个算几个,但是限制只允许调用一次接口,接口响应之后才会发起下次请求.这样就大大减少了对服务器的冲击;
2.单个接口查询查询速度过慢
只输入一个字符之后响应时间很长,看了一下控制台的响应时间大概是15秒.猜测此处存在慢sql.
问题处理
对于问题1主要是前端访问方式的处理,问题分析中已经将处理方式做了说明,此处不再多说。主要是从服务端说一下问题2的处理过程.
以下是此场景的数据库查询sql:
SELECT DISTINCT(staff_card.`card_no`) card_no,staff.`real_name`,staff.`mobile`,card.`card_name`,staff_card.`status`,card.id card_id FROM studio LEFT JOIN staff ON staff_studio.`login`=staff.`login` LEFT JOIN staff_card ON staff_card.`login`=staff.`login` LEFT JOIN card ON staff_card.`card_id`=card.`id` LEFT JOIN card_course ON card_course.`card_id`=staff_card.`card_id` WHERE ((staff_studio.`state`=1 AND staff_studio.`studio_id`=2 AND staff_card.`studio_id`=2) OR (card.`flag`=1 AND card_course.`studio_id`=2 )) AND staff_card.`status` IN (1,4) AND CONCAT(staff.`mobile`,staff.`real_name`,staff_card.`card_no`) LIKE CONCAT('%', '1','%')
数据库执行时间在11秒.
使用explain进行执行计划查询,发现type字段中有多个all,表示是全表扫描,经过多次尝试,主要做两个处理:
1.使用union all 代替or
SELECT taff_card.`card_no`,staff.`real_name`,staff.`mobile`,card.`card_name`,staff_card.`status`,card.id card_id FROM staff_studio LEFT JOIN staff ON staff_studio.`login`=staff.`login` LEFT JOIN staff_card ON staff_card.`login`=staff.`login` AND staff_card.`studio_id`=staff_studio.`studio_id` AND staff_card.`status` IN (1,4) LEFT JOIN card ON staff_card.`card_id`=card.`id` WHERE staff_studio.`state`=1 AND staff_studio.`studio_id`=2 AND CONCAT(staff.`mobile`,staff.`real_name`,staff_card.`card_no`) LIKE CONCAT('%', ‘1’,'%') UNION ALL SELECT staff_card.`card_no`,staff.`real_name`,staff.`mobile`,card.`card_name`,staff_card.`status`,card.id card_id FROM staff_studio LEFT JOIN staff ON staff_studio.`login`=staff.`login` LEFT JOINstaff_card ON staff_card.`login`=staff.`login` LEFT JOIN card ON staff_card.`card_id`=card.`id` LEFT JOIN card_course ON card_course.`card_id`=staff_card.`card_id` WHERE card.`flag`=1 AND card_course.`studio_id`=2 AND staff_card.`status` IN (1,4) AND CONCAT(staff.`mobile`,staff.`real_name`,staff_card.`card_no`) LIKE CONCAT('%', ‘1’,'%')
2.添加索引
将explain查询中type为all的表按照查询条件或left关联字段进行添加索引,执行sql如下:
-- manage_staff_studio添加索引login ALTER TABLE manage_staff_studio ADD INDEX index_login (login); -- manage_staff_card添加索引login ALTER TABLE manage_staff_card ADD INDEX index_login (login); -- manage_card_course添加索引card_id ALTER TABLE manage_card_course ADD INDEX index_card (card_id);
添加之后测试查询速度变为0.029秒;慢sql问题处理
反思总结
由于业务设计原因,对于个别字段存在重复情况,原来使用distinct进行处理,但是使用explain查询之后发现extra中存在using temporying.查询了相关资料得知using temporying一般是进行distinct或是group by操作都会导致生成临时表,一般出现临时表是需要优化的,但是想说的是凡事没有绝对,别人说的结论自己动手要去尝试验证。只要查询速度能提升上来,出现此提示不处理也可以.后期如果需要对distinct优化等同于group by进行优化,官方文档中对此有所介绍.官方参考链接:
https://dev.mysql.com/doc/refman/8.0/en/distinct-optimization.html。
另外说一下线上业务场景与问题定位的思路,对于服务端而言,服务端项目所部署的服务器和数据库所在服务器可能不是一个,需要分别对对应的服务器进行查看监控信息,项目中服务器都是使用的阿里云,可以通过阿里云控制台看下各项监控信息.上面的场景中存在的问题还在于发起很多个请求没有响应的情况下,打开别的页面会出现网络异常提示,对应时间节点看数据库服务器监控信息,当时CPU已经达到100%.所以其他页面不能打开也就能解释清楚了。
如果想看详细的服务器信息可以使用atop工具进行监控,可以实时输出监控日志信息,结合服务端项目业务日志更容易进行定位问题。atop安装参考链接:
https://help.aliyun.com/document_detail/101877.html
cpu达到100%处理方案:1.升级CPU,2.业务侧优化,主要服务器上各应用CPU占比,针对性优化.一般是对数据库或是java项目进行优化。
以上是处理网站性能优化的记录和总结,如果看完感觉有所收获环境评论区点赞或留言!