一次慢SQL优化

问题
查询语句
SELECT `type`,COUNT(*) as num FROM th_mkt_push_message_box_? where user_id = '?' AND is_read = ? GROUP BY `type`;
慢SQL分布情况

在这里插入图片描述
可以看出慢SQL基本集中在中午12点与下午2点。

分析
Step 1 影响范围

  根据影响范围确定问题等级,制定修改方案与排期。该慢SQL为首页接口,QPS100+,慢SQL出现集中在12点和16点左右频率2s一次,平均耗时100ms,暂时未对业务产生影响。

Step 2 缓存问题

  因为C端场景对RT时间比较敏感,所以在分析C端的慢SQL时需要先确定该场景下有没有使用缓存来提高访问速度。
  该场景下使用Codis缓存了用户未读消息数量,默认过期时间为7天,
在这里插入图片描述
消息插入

  • num == 0,从数据库同步缓存数据
  • num > 0,缓存num原子自增

接口查询

  • num == 0,从数据库同步缓存数据
  • num > 0,直接返回缓存数据

  用户的未读消息数量通常是不为0的,因此缓存可以处理大部分的请求数据。但是仍有一小部分流量会击穿缓存访问到数据库,如果数据库这部分用户的未读消息也为0,就会造成缓存穿透
  另外,消息插入缓存数量自增时并没有更新缓存时间,所以慢SQL集中出现在下午12点与16点左右,实际上这个时间段是插入的流量高峰期,随着部分缓存过期,造成了缓存雪崩

Step 3 数据量

  目前消息数据量保持在4亿左右,每日插入量200万左右,每日凌晨执行过期计划过期200万左右数据。数据存储使用分表形式,分了64张表,每张表数据量在600万左右,不会影响索引查询。

Step 4 SQL语句

首先Explain一下慢SQL语句
在这里插入图片描述
主要看下type(查询类型),key(使用索引),rows(扫描行数)和Extra属性。
这条查询走了索引,使用index索引(userId),因为索引信息未覆盖查询结果导致了回表查询。

小结
缓存失效问题

   使用缓存要注意的问题

  • 缓存的失效策略
  • 缓存的同步策略

消息插入:当缓存不为0时,自增时需要更新消息过期时间。
接口查询:缓存为0时,可以不走同步策略,因为只有用户一周内无消息,或者刚清空消息时缓存消息可能为0。

SQL优化问题
 user_id = '?' AND is_read = ? GROUP BY `type`;

  根据上面SQL语句应该建立联合索引(user_id,is_read,type),来确保查询时不需要再次过滤条件,返回时不需要回表查询。

  • Using index; 索引覆盖
  • Using index;Using where;索引覆盖且过滤结果
  • Using index Condition;索引未全覆盖,筛选条件为前导列
  • Using where; 索引未覆盖,筛选条件非索引
反思

  传统的OLTP系统,在设计阶段就会考虑到数据量和访问量的问题。系统上线后,在系统没有bug的情况下依靠SQL优化很难解决慢SQL问题,因此SQL优化的优先级并不高,如果上述步骤依然没办法解决问题,只能考虑动态扩展数据库资源。
  在需要分表的场景下,要在设计阶段把查询的场景的索引确定好,不然项目上线以后加索引就变成了一个十分繁琐的操作。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值