前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >存储优化(2)-排序引起的慢查询优化

存储优化(2)-排序引起的慢查询优化

作者头像
方丈的寺院
发布2020-03-20 09:50:54
9240
发布2020-03-20 09:50:54
举报
文章被收录于专栏:方丈的寺院

摘要

排序引起的慢查询,通常不是那么容易发现,经常和数据分布有关系。往往在业务刚开始时并没有什么问题,但是随着业务的发展,数据分布呈现一种特定的规律,导致了慢查询,或者并不是什么慢查询,但是随着并发请求数增加,数据库的IOPS使用率变高,进一步导致cpu/内存使用率飙高。造成线上故障。

问题

因为排序引起的问题遇到很多次

例1:某日收到线上cpu告警

然后查看慢sql日志 大量的慢查询指向了这个查询

代码语言:javascript
复制
SELECT
        id,
        prize_id,
        user_id,
        name,
        biz_id
        FROM play
        WHERE biz_id = xx
        AND status = 1
        AND prize_type = '大奖'
        ORDER BY id DESC
        LIMIT 0, 10

play是抽奖记录表,sql是查抽中奖品的前10个大奖中奖者,来吸引其他用户参与抽奖,biz_id建了索引

例2 某日上线一个新功能,在第五次压测时,数据库cpu告警

查看数据库慢日志,没有一条慢sql(耗时>100ms)。最后通过查阅代码,sql调用统计。发现有大量下面的SQL调用

代码语言:javascript
复制
SELECT
        id,
        commit_id
        FROM commit_record
        WHERE biz_id = 'xxx' 
        AND id >=  #{fromId}
       AND id <= #{toId}

biz_id有索引

例3 某日线上服务报警:API响应时间超过X毫秒

通过查看应用日志,发现大量 com.mongodb.MongoSocketReadTimeoutException:mongo的错误。经过多重定位,发现从库的IOPS使用率快接近100%了,同时发现有些慢查询

代码语言:javascript
复制
"query":{"find":"historyRecord","filter":{"bizId":1234567,"version":23},"sort":{"_id":-1},"limit":1}}

索引是bizId,version的联合索引

问题分析

这几个查询造成的线上问题的形式虽然各有不同,但本质上都是一样,无法利用索引排序,需要用到数据库排序,当内存够大或没超过排序上限时,就会在内存中排序,这样单个查询相对比较快,但是并发量高了,内存容量不够了,需要进行磁盘排序时,就会变得很慢。

然后经过仔细观察,发现容易写出这种语句,忽视了排序造成的风险。常常是根据主键排序。开发者容易想当然的以为主键是有索引的,所以排序会走索引,所以不会有什么大问题。但其实像例子中那些案例,都是无法利用索引排序的。曾经在mongo索引篇介绍联合索引如何创建时也提到过。

总结一下,造成数据库服务问题主要根由是

  1. 查询没有利用到索引排序
  2. 索引过滤后下面数据仍然有很多,需要扫描排序的数据很多
  3. 请求的并发量很高,数据库IOPS使用率高,内存占用高。

问题解决

首先,日常开发时避免写出这种SQL,尤其针对数据量比较大的表。或者索引下数据分布可能不均匀的情况。

线上解决收到线上警告,发现是此类问题。

  1. 判断业务侧能否降级,即减少此类查询。确保不要影响其他业务。
  2. 数据库升级配置(需要做到对业务无影响)

线上问题的临时解决方案只能解一时燃煤之急,真正的解决问题还是需要从查询着手。

查询优化

  1. 业务侧避免此类查询 从业务侧分析,是不是需要此类查询。比如例3,bizId,versionid是不是本身可以作为有序的,版本号versionid可以设计成有序的,这样就不需要根据主键_id来保持有序
  2. 减少并发 是不是所有的这类查询都是必须的,能不能接受缓存。
  3. 引入其他存储方案 比如例1,业务需要查询按照时间顺序的中大奖的前N个人。这个业务侧可以将数据保存到在redis中,listz中存topN的数据。然后发现有中大奖的人,扔到redis队列即可。
  4. 增加一个联合索引 比如例3可以增加一个bizId,version,_id联合索引 "query":{"find":"historyRecord","filter":{"bizId":1234567,"version":23},"sort":{"_id":-1},"limit":1}}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 方丈的寺院 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 摘要
  • 问题
    • 例1:某日收到线上cpu告警
      • 例2 某日上线一个新功能,在第五次压测时,数据库cpu告警
        • 例3 某日线上服务报警:API响应时间超过X毫秒
        • 问题分析
        • 问题解决
        相关产品与服务
        云数据库 Redis®
        腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档