是否开启了慢查询记录
选择某一数据库,执行db.getProfilingStatus()
,可得到如下结果:
was=1表示开启了慢查询记录,0表示未开启
showms表示记录超过多少ms的数据库操作
开启记录慢查询
开始方法有2种
选中某一数据库后,shell里执行db.setProfilingLevel(1,200)
,其中,参数1表示记录的级别,参数2表示记录大于多少ms的操作
0:关闭,不收集任何数据。
1:收集慢查询数据,默认是100毫秒。
2:收集所有数据
#也可以MongoDB启动时,开启Profiling
mongod --profile=1 --slowms=200
#或者在配置文件里添加
profile = 1
slowms = 200
分析方法
查看system.profile表,里面会记录所有慢查询记录
其中一条的详细说明如下:
#下面是一个超过200ms的查询语句
{
"op" : "query", #操作类型,有insert、query、update、remove、getmore、command
"ns" : "F10data3.f10_2_8_3_jgcc",
"query" : { #具体的查询语句 包括过滤条件,limit行数 排序字段
filter" : {
"jzrq" : {
"$gte" : ISODate("2017-03-31T16:00:00.000+0000"),
"$lte" : ISODate("2017-06-30T15:59:59.000+0000")
},
"jglxfldm" : 10.0
},
"ntoreturn" : 200.0,
"sort" : { #如果有排序 则显示排序的字段 这里是 RsId
"RsId" : 1.0
}
},
"keysExamined" : 0.0, #索引扫描数量 这里是全表扫描,没有用索引 所以是 0
"docsExamined" : 69608.0, #浏览的文档数 这里是全表扫描 所以是整个collection中的全部文档数
"numYield" : 546.0, #该操作为了使其他操作完成而放弃的次数。通常来说,当他们需要访问
还没有完全读入内存中的数据时,操作将放弃。这使得在MongoDB为了
放弃操作进行数据读取的同时,还有数据在内存中的其他操作可以完成。
"locks" : { #锁信息,R:全局读锁;W:全局写锁;r:特定数据库的读锁;w:特定数据库的写锁
"Global" : {
"acquireCount" : {
"r" : NumberLong(1094) #该操作获取一个全局级锁花费的时间。
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(547)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(547)
}
}
},
"nreturned" : 200.0, #返回的文档数量
"responseLength" : 57695.0, #返回字节长度,如果这个数字很大,考虑值返回所需字段
"millis" : 264.0, #消耗的时间(毫秒)
"planSummary" : "COLLSCAN, COLLSCAN", #执行概览 从这里看来 是全表扫描
"execStats" : { #详细的执行计划 这里先略过 后续可以用 explain来具体分析
},
"ts" : ISODate("2017-08-24T02:32:49.768+0000"), #命令执行的时间
"client" : "10.3.131.96", #访问的ip或者主机
"allUsers" : [
],
"user" : ""
}
常见问题:
1. 如果发现 millis 值比较大,那么就需要作优化。
2. 如果docsExamined数很大,或者接近记录总数(文档数),那么可能没有用到索引查询,而是全表扫描。
3. 如果keysExamined数为0,也可能是没用索引。
4. 结合 planSummary 中的显示,上例中是 "COLLSCAN, COLLSCAN" 确认是全表扫描
5. 如果 keysExamined 值高于 nreturned 的值,说明数据库为了找到目标文档扫描了很多文档。这时可以考虑创建索引来提高效率。
6. 索引的键值选择可以根据 query 中的输出参考,上例中 filter:包含了 jzrq和jglxfldm 并且按照RsId排序,所以 我们的索引
索引可以这么建: db.f10_2_8_3_jgcc.ensureindex({jzrq:1,jglxfldm:1,RsId:1}
planSummary的其他类型可选项:
COLLSCAN #全表扫描 避免
IXSCAN #索引扫描 可以改进 选用更高效的索引
FETCH #根据索引去检索指定document
SHARD_MERGE #将各个分片返回数据进行merge 尽可能避免跨分片查询
SORT #表明在内存中进行了排序(与老版本的scanAndOrder:true一致) 排序要有index
LIMIT #使用limit限制返回数 要有限制 Limit+(Fetch+ixscan)最优
SKIP #使用skip进行跳过 避免不合理的skip
IDHACK #针对_id进行查询 推荐,_id 默认主键,查询速度快
SHARDING_FILTER #通过mongos对分片数据进行查询 SHARDING_FILTER+ixscan最优
COUNT #利用db.coll.explain().count()之类进行count运算
COUNTSCAN #count不使用Index进行count时的stage返回 避免 这种情况建议加索引
COUNT_SCAN #count使用了Index进行count时的stage返回 推荐
SUBPLA #未使用到索引的$or查询的stage返回 避免
TEXT #使用全文索引进行查询时候的stage返回
PROJECTION #限定返回字段时候stage的返回 选择需要的数据, 推荐PROJECTION+ixscan