分析MongoDB数据库的慢请求
云数据库MongoDB默认开启了慢请求Profiling ,系统自动地将请求时间超过100ms的执行情况记录到对应数据库下的system.profile集合里。
通过use 命令进入指定数据库。 use mongodbtest
执行如下命令,查看该数据下的慢请求日志。 db.system.profile.find().pretty()
分析慢请求日志,查找引起MongoDB CPU使用率升高的原因。
以下为某个慢请求日志示例,可查看到该请求进行了全表扫描,扫描了11000000个文档,没有通过索引进行查询。 {
"op" : "query",
"ns" : "123.testCollection",
"command" : {
"find" : "testCollection",
"filter" : {
"name" : "zhangsan"
},
"$db" : "123"
},
"keysExamined" : 0,
"docsExamined" : 11000000,
"cursorExhausted" : true,
"numYield" : 85977,
"nreturned" : 0,
"locks" : {
"Global" : {
"acquireCount" : {
"r" : NumberLong(85978)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(85978)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(85978)
}
}
},
"responseLength" : 232,
"protocol" : "op_command",
"millis" : 19428,
"planSummary" : "COLLSCAN",
"execStats" : {
"stage" : "COLLSCAN",
"filter" : {
"name" : {
"$eq" : "zhangsan"
}
},
"nReturned" : 0,
"executionTimeMillisEstimate" : 18233,
"works" : 11000002,
"advanced" : 0,
"needTime" : 11000001,
"needYield" : 0,
"saveState" : 85977,
"restoreState" : 85977,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
....in"
}
],
"user" : "root@admin"
}
通常在慢请求日志中,您需要重点关注以下几点。
全表扫描(关键字: COLLSCAN、 docsExamined )
全集合(表)扫描COLLSCAN 。
当一个操作请求(如查询、更新、删除等)需要全表扫描时,将非常占用CPU资源。在查看慢请求日志时发现COLLSCAN关键字,很可能是这些查询占用了CPU资源。
说明 如果这种请求比较频繁,建议对查询的字段建立索引的方式来优化。
通过查看docsExamined的值,可以查看到一个查询扫描了多少文档。该值越大,请求所占用的CPU开销越大。
不合理的索引(关键字: IXSCAN、keysExamined )
说明
索引不是越多越好,索引过多会影响写入、更新的性能。
如果您的应用偏向于写操作,索引可能会影响性能。
通过查看keysExamined字段,可以查看到一个使用了索引的查询,扫描了多少条索引。该值越大,CPU开销越大。
如果索引建立的不太合理,或者是匹配的结果很多。这样即使使用索引,请求开销也不会优化很多,执行的速度也会很慢。
如下所示,假设某个集合的数据,x字段取值的重复率很高(假设只有1、2),而y字段取值的重复率很低。{ x: 1, y: 1 }
{ x: 1, y: 2 }
{ x: 1, y: 3 }
......
{ x: 1, y: 100000}
{ x: 2, y: 1 }
{ x: 2, y: 2 }
{ x: 2, y: 3 }
......
{ x: 1, y: 100000}
要实现 {x: 1, y: 2} 这样的查询。db.createIndex( {x: 1} ) 效果不好,因为x相同取值太多
db.createIndex( {x: 1, y: 1} ) 效果不好,因为x相同取值太多
db.createIndex( {y: 1 } ) 效果好,因为y相同取值很少
db.createIndex( {y: 1, x: 1 } ) 效果好,因为y相同取值少
关于{y: 1} 与 {y: 1, x: 1} 的区别,可参见
大量数据排序(关键字: SORT、hasSortStage )
当查询请求里包含排序的时候, system.profile 集合里的hasSortStage字段会为 true 。如果排序无法通过索引满足,MongoDB会在查询结果中进行排序。而排序这个动作将非常消耗CPU资源,这种情况需要对经常排序的字段建立索引的方式进行优化。
说明 当您在system.profile集合里发现SORT关键字时,可以考虑通过索引来优化排序。
其他还有诸如建立索引、aggregation(遍历、查询、更新、排序等动作的组合) 等操作也可能非常耗CPU资源,但本质上也是上述几种场景。更多profiling的设置请参见
您也可以将MongoDB实例接入至数据库自治服务DAS(Database Autonomy Service)。在DAS控制台中,您可以对MongoDB实例的实时性能、实时会话、慢日志、磁盘空间等信息进行监控和管理,详情请参见