排序引发的慢查询,一般不是那么容易发现,常常和数据分布有关系。每每在业务刚开始时并无什么问题,可是随着业务的发展,数据分布呈现一种特定的规律,致使了慢查询,或者并非什么慢查询,可是随着并发请求数增长,数据库的IOPS使用率变高,进一步致使cpu/内存使用率飙高。形成线上故障。redis
由于排序引发的问题遇到不少次sql
而后查看慢sql日志 大量的慢查询指向了这个查询mongodb
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建了索引数据库
查看数据库慢日志,没有一条慢sql(耗时>100ms)。最后经过查阅代码,sql调用统计。发现有大量下面的SQL调用缓存
SELECT
id,
commit_id
FROM commit_record
WHERE biz_id = 'xxx'
AND id >= #{fromId}
AND id <= #{toId}
复制代码
biz_id有索引bash
经过查看应用日志,发现大量com.mongodb.MongoSocketReadTimeoutException:
mongo的错误。通过多重定位,发现从库的IOPS使用率快接近100%了,同时发现有些慢查询并发
"query":{"find":"historyRecord","filter":{"bizId":1234567,"version":23},"sort":{"_id":-1},"limit":1}}
复制代码
索引是bizId,version的联合索引优化
这几个查询形成的线上问题的形式虽然各有不一样,但本质上都是同样,没法利用索引排序,须要用到数据库排序,当内存够大或没超过排序上限时,就会在内存中排序,这样单个查询相对比较快,可是并发量高了,内存容量不够了,须要进行磁盘排序时,就会变得很慢。spa
而后通过仔细观察,发现容易写出这种语句,忽视了排序形成的风险。经常是根据主键排序。开发者容易想固然的觉得主键是有索引的,因此排序会走索引,因此不会有什么大问题。但其实像例子中那些案例,都是没法利用索引排序的。 曾经在mongo索引篇介绍联合索引如何建立时也提到过。.net
总结一下,形成数据库服务问题主要根由是
首先,平常开发时避免写出这种SQL,尤为针对数据量比较大的表。或者索引下数据分布可能不均匀的状况。
线上解决 收到线上警告,发现是此类问题。
线上问题的临时解决方案只能解一时燃煤之急,真正的解决问题仍是须要从查询着手。
查询优化
"query":{"find":"historyRecord","filter":{"bizId":1234567,"version":23},"sort":{"_id":-1},"limit":1}}
复制代码