Mysql慢查询漫谈

何为慢查询:

‌‌ 数据库慢查询是一个相对的概念,在日常的服务结构中,服务提供的接口很多时候是需要从数据库获取数据来提供服务的.这个时候就会有数据库的交互. 作为服务端来讲.更短的响应时间意味着更好的服务.平均响应时长是一个衡量接口的非常重要的指标.

慢查询是通过综合度量服务的整体平均响应时间来度量的一个相对值.如果服务提供的接口平均响应速度为50ms.平均的数据库交互时长是30ms .那么我们可以定义数据库的慢查询时长为50ms.如果数据库的执行时间超过这个阈值,就认为是慢查询.具体的定义并不是拍脑门想出来的.是通过整体的相应时间来衡量和计算的 .

作为服务来讲,数据库查询的耗时越少越好,因为越少的执行时间意味着越快的接口响应速度.越快的响应速度意味着接口的优性能化越好.

用最简单的例子来说明,我们有一个获取用户信息的接口,这个接口的名字叫getuserinfo . 在查询用户信息的过程中,会在服务端根据请求参数获得的用户ID,再去通过用户ID去数据库中查询用户的信息,最后组织并返回.此时会产生一次数据库交互,如果此时我们的数据库中用户的id并不是主键.在表数据量比较多的情况下就会造成这个查询语句在数据库执行层面耗时很长.原因是非索引字段的查询会造成全表扫描.

所以我们可以得到一个相对的概念: 所谓数据库的慢查询,是指接口维度的数据库交互时间超过了整体的平均交互时间 一定量 的数据库交互.

慢查询造成的影响

其实上面已经说过了,慢查询造成的影响包括但不限于:

  • 增加接口的响应时长.从而间接增加整体服务的平均响应时长,进一步影响整个集群的可用性.
  • 大量慢查询会导致数据库的session长期被占用.造成共同使用的其他服务或者接口连接数据库失败.
  • 增加mysql的CPU和内存的使用率,导致mysql的服务可用性下降.
  • 服务接口的整体耗时增长间接导致服务的整体可用性下降(5xx错误和超时).
  • 带宽长期占用,导致影响到其他服务.

数据库慢查询出现的一般情况和办法:

搞清楚了什么是数据库慢查询.就要研究一下为什么会出现慢查询.

总的来说:

一些不当的数据库操作会造成慢查询,说慢查询,其实更确切一点的描述是,慢执行.在整个接口运行的过程中,有一些步骤造成了预期外的耗时.有一些行为是不应该在接口里面来操作的,或者说不应该让用户感知到.还是举一些具体的例子:

  • 大批量的更新数据

我们去更新一个表里面的所有行的某个字段,这种操作不应该出现在接口层面.因为这样的操作对数据库来说时间复杂度为O(N),N为数据行数.

解决: 这样的查询和更新就不应该出现在服务中.

  • 不恰当的汇总数据

去根据一些条件进行数据汇总,如果这样的情况不可避免,那么也应该合理去设计缓存.避免直接去操作数据库.同样是O(N).

解决: 这样的情况真的不应该出现在服务中.如果有,就应该和上面的问题一样,好好反思这个设计.

  • 大量数据操作

一次性取非常多的数据量,会导致IO问题,比如我们一次从数据库获取1000条数据,每条数据2K,那么这样的请求一个请求就会占用10002k = 2M的 带宽,这样的操作如果有1000QPS ,那么一秒中的带宽占用就是 10002M = 2G,这样的带宽占用对于一个服务器来说是致命的. 解决办法就是合理的设计接口和服务,该分页分页,只取需要的字段.不要动不动就select * .

  • 耗时较长的事务操作

当我们开启一个事务的过程中,会导致数据库给事务涉及的数据上锁,所有其他需求该行数据的请求都会受到影响, 所以耗时较长的事务,应该考虑是否能够用分布式事务的方式来处理.并且一些情况下 我们需要考虑是否能够不使用事务.

  • 联表查询

联合查询在一些情况下也会造成数据库的慢查询,主要是因为在联表查询的过程中,数据库的执行过程往往很难用到索引.可以考虑是否能够通过冗余一些数据来避免联表查询,空间换时间.拆分查询到单独的表上,并使用索引.

  • 非索引查询

在数据库的交互过程中,索引起到了至关重要的作用,合理的建立数据的索引能够很大程度上的避免造成慢查询.而慢查询出现最多的场景,往往就是没有正确建立索引.

上面只说了一般情况下的慢查询,但是很多时候我们还会遇到一些很棘手的问题,造成慢查询的原因还有很多很多,有的是会后很诡异,甚至是神奇.

发现慢查询

我们知道了慢查询出现的一般情况,那么要怎么去发现慢查询呢.

从业务方角度:

从数据库的使用方,也就是mysql的上游,去统计每个执行的耗时.把耗时过长的执行输出到日志中,并做好监控,这是一个很好的方法,这样的方法能够正向的去发现mysql使用过程中的慢查询.这主要是RD来做的事情.因为对业务的了解,RD发现问题后能够更好的去提出应对和解决方案.

从服务方角度:
mysql也提供了相当多的方法和工具来找到慢查询. 比如mysql里面可以通过配置来记录慢查询.这一般是数据库运维人员也就是DBA操心的事情.如果由DBA反馈给服务方.这样的方式就是逆向的了.时效性可能会有折扣.另外DBA不一定了解业务,很多时候不确定慢查询造成的影响到底有多大.可能很火急火燎的来找RD ,但是RD一看觉得没什么.又有可能觉得只是个小问题.但是影响了核心业务.

其实解决慢查询最好的方式就是,在写查询的过程中,知道自己在干什么,数据库会怎么执行.需要怎么样的数据表索引来配合这个查询.所谓熟能生巧.

合理的慢查询

既然慢查询都已经影响了线上的服务了,那咋还能有合理的慢查询.虽然数据库的慢查询不应该出现,但是有些情况下我们是不能够避免的.
还是举例来说:

如果我需要针对线上数据库做汇总,加工数据然后存入缓存.那么我汇总的过程中,很多时候是会造成慢查询的.这个需求可能是合理的,这个时候可以考虑尽量把影响降到最低.

如果我需要针对数据做批量更新.每个月一次,批量清除历史数据,这个时候势必会造成慢查询.可以考虑吧这样的操作分散开,避免集中处理.

最后的最后,慢查询不是个好东西.应该尽量把它扼杀掉.

Show Comments
备案信息: 京ICP备20002019号