记一次mysql查询慢的优化历程
Posted 公号运维家
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次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实施运维工程师,呼叫中心运维工程师面试
腾讯idc运 维工程师面试,运维工程师samba,运维工程师的行业是什么,
运维工程师的来历,运维工程师好找嘛,运维 工程师出入,运维工程师自学可行
以上是关于记一次mysql查询慢的优化历程的主要内容,如果未能解决你的问题,请参考以下文章