在存储优化(2)-排序引发的慢查询优化中咱们提到过排序对查询选择索引的影响。可是的解决办法就是增长一个索引。在线上给mongo的大表增长一个索引要慎重。在增长索引的过程当中也遇到了一些问题,这边进行相关的记录与分析。sql
表结构mongodb
_id,
biz_Id,
version,
name
复制代码
索引数据库
1. 主键索引
2. biz_id,version联合索引
复制代码
查询语句缓存
"query":{"find":"historyRecord","filter":{"bizId":1234567},"sort":{"_id":-1},"limit":1}}
复制代码
增长一个索引bash
bizId,_id
复制代码
对于大表(该表记录数5亿),创建索引过程涉及到锁表,大量的读写操做、数据同步,确定会影响线上的操做。因此选择在业务低谷期,创建一个background的index,这样不会锁表。 注:优化
mongo4.2之后优化了创建索引过程,不须要background参数了https://docs.mongodb.com/manual/reference/command/createIndexes/#dbcmd.createIndexesspa
建立完索引后,经过客户端链接,查看执行计划,始终扫描一行。完美,走到了新的索引。.net
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 0,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1
复制代码
而后再观察几天慢sql,大吃一惊发现仍是存在慢查询,可是相同的语句,放到客户端查询的时候,又是执行的新索引。查看system.profiles中慢日志日志
当时这条慢查询语句走的是cached_plan. code
那是否是由于这个索引是后来加的,plan-cache尚未更新的。清理掉执行计划缓存,执行操做
db.historyRecord.getPlanCache().clear()
复制代码
继续观察,发现并无什么用。百思不得其解,在深刻解析 MongoDB Plan Cache找到一些思路,MongoDB的执行计划
看了下缓存计划中的
db.getCollection('historyRecord').getPlanCache().listQueryShapes()
{
"query" : {
"bizId" : "xxxxx"
},
"sort" : 0
"_id" : -1.0
},
"projection" : {}
},
复制代码
而该查询使用"bizId,version"索引,而bizId="xxxx"下面的索引值是100左右。咱们的数据分布,bizId,version在100之内的多是95%,只有5%的在100以上,这会给索引判断形成误判。
最后解决是经过强制索引来避免索引误判,固然也能够将排序改为
sort({bizId:-1,_id:-1})
复制代码
这样也不会误判
总结一下: