记一次mysql查询慢的优化历程

图片

有一个项目,代称cc,用了我们公司的产品,单表数据量在200万左右。在做业务操作的时候,点击一下按钮,需要等待2~3分钟。及其难以忍受,特此让我们修改。

PS:涉及的一些sql命令,简化了很多,不能暴露线上信息。

第一反应

当收到这个问题的时候,第一反应就是确定下到底是后台数据查询慢,还是前端数据渲染慢,亦或者是网慢,那么如何排查呢?

询问客户使用了产品的哪个功能,然后自己模拟一下,并使用F12,追踪下总的时间,是否如客户所说的时长;

定位问题

结果,果然,点击一下然后就开始了漫长的等待,竟然真的需要2~3分钟,完成一个业务流竟然需要10分钟(该业务流需要多次点击菜单处理数据)。

验证客户所说为真。

和网速没关系;

那么接下来验证下是前端还是后台慢;

看下mysql数据库的慢sql记录,是否存在长时间的sql语句。

如果mysql没有配置慢sql记录,那么首先我们要进行如下配置:

vim /etc/my.cnf
# 在 [mysqld] 模块中
slow-query-log=On
slow_query_log_file="/data/mysql/localhost-slow.log"

配置完毕之后,需要重启下mysql服务。

systemctl restart mysqld.service

而后再次模拟cc客户反馈慢的地方,运行完毕之后,看下存储慢sql文件的地方,里面是否有数据;

vim /data/mysql/localhost-slow.log

果然有,而且时间和前端展示的总时间差不太多,说明响应慢的问题,一大半的原因是因为数据库慢所导致的。其他的就是前端数据渲染慢+服务中转+网速问题了。

解决思路

数据库sql慢的思路:

首先我们需要找到所有的慢sql,找到之后,第一反应应该是查有没有配置索引,有没有添加索引,使用explain + sql 的方式来查看,例如:

explain select (*) from ceshi_1;

在展示的信息中,各个参数含义如下:

  • id:选择标识符

  • select_type:表示查询的类型

  • table:输出结果集的表

  • partitions:匹配的分区

  • type:表示表的连接类型

  • possible_keys:表示查询时,可能使用的索引

  • key:表示实际使用的索引

  • key_len:索引字段的长度

  • ref:列与索引的比较

  • rows:扫描出的行数(估算的行数)

  • filtered:按表条件过滤的行百分比

  • Extra:执行情况的描述和说明

根据possible_keyskey即可看到是否配置和使用了索引,如果没有就添加,如果有就检查其他问题。

前端慢的思路:

需要看下前端资源是否进行了压缩传输,以及网速问题;

大概率情况下,网速一般是不需要解决的,除非说这个项目是刚上线就特别慢,这种情况才需要解决网速问题,所以我们只需要看下前端资源是否进行了压缩传输即可。

前端一般使用的是nginx;我们看下是否进行了如下配置:

gzip on;
gzip_buffers 32 4k;
gzip_comp_level 2;
gzip_min_length 300k;
gzip_types text/plain  application/x-javascript application/javascript application/xml text/css text/javascript image/jpeg image/gif image/png;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;

以上内容,应该配置在nginx中的conf/nginx.conf文件中的http/server中的listen参数下;

然后重新加载下nginx的配置文件,让其生效,使用如下命令:

./sbin/nginx -s reload

最常见的解决方式就是按照上面的来,一般都能解决。

但是

但是

但是

但是

但是

我这里不好使,为什么呢?往下看。

实际解决方案

上面不是说了嘛,总的来说,慢的有两个地方,一个是sql查询慢,还有一个就是前端加载慢(有部分影响)。前端就按照上面的解决没问题,但是sql就不太行。

为啥呢,因为程序里面实现某一功能的sql,咋说的,写的有点儿烂,怎么个烂法呢,跨表查询+嵌套查询+group by+limit+like+时间范围查询。就导致了虽然这个sql中涉及的每个表的使用字段都配置了索引,但是并没有命中,相当于无效了,而且,还不好弄。

当然了,最好的方式是让程序修改里面定义的sql文件嘛,但是嘛。。。懂的都懂。

最后,通过在mysql中添加缓存,这个缓存的作用是什么呢,就是说,当你执行了一条sql,比如是:

select a,b,b from test_1 where time = '2022-07-27';

你第一次执行这个命令的时候,mysql的缓存会把这个sql和结果存放到缓存中。

只要你涉及到这个查询的数据没有变化,那么你后面再次查询的时候,就不执行查询了,而是直接把缓存中的这个结果返回,这样子就大大减少了查询时间。

怎么配置呢,还是需要修改mysql的配置文件:

query_cache_size=2048M  # 缓存大小
query_cache_type=1  # 开启缓存

然后重启下数据库;

systemctl restart mysqld.service

当然了,也可以使用global set的方式临时进行修改。

这样子添加完之后,只有第一次访问慢,后面就非常快了。

通过上面的操作之后,点击菜单的时间从2~3分钟,优化到了14秒左右,客户还是不是很满意,因为他们需要操作的业务量还是挺大的。

那么有没有别的办法呢,再次研究程序里面定义的sql,看看是否能通过添加联合索引,或者其他索引的方式来优化,你别说,还真的让我发现了一个索引,添加完毕之后,时间再次砍半,由14秒,再次缩短到了7秒左右,这个时候客户终于临时接受了,并发函让我们继续整改。

我们也承诺会进行排期优化sql,并及时上线。

事情也就到此为止告一段落了。

总结

遇到这种数据库慢的情况,无非就是先定位问题,然后再根据情况来优化,大概率是sql本身的问题,上线之初可能没有进行审核,只是为了上线而上线了,测试数据也就几百几千条,完全没有压力测试吧。

这个处理方式,仅供参考,不可能所有的都可以按照这个方式来处理,你如果有更好的方式,欢迎通过公众号“运维家”,来添加我的微信来和我交流。

至此,本文结束。

更多内容请转至VX公众号 “运维家” ,获取最新文章。

------ “运维家” ------

------ “运维家” ------

------ “运维家” ------

临武县运维工程师培训,温州运维工程师,通达oa实施运维工程师,呼叫中心运维工程师面试
腾讯idc运 维工程师面试,运维工程师samba,运维工程师的行业是什么,
运维工程师的来历,运维工程师好找嘛,运维 工程师出入,运维工程师自学可行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

运维家

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值