天天看点

记一次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_keys​

​​和​

​key​

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

前端慢的思路:

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

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

前端一般使用的是​

​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​

​本身的问题,上线之初可能没有进行审核,只是为了上线而上线了,测试数据也就几百几千条,完全没有压力测试吧。

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

至此,本文结束。 

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

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

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

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

临武县运维工程师培训,温州运维工程师,通达oa实施运维工程师,呼叫中心运维工程师面试