Meng Xin Zhu

MongoDB是目前最为流行的NoSQL数据库之一。V秘的后台数据就是保存在MongoDB中的哦;)

尽管MongoDB的性能为业界称道,但任何数据库系统使用中都存在着慢查询的问题。慢查询的性能问题,可能是由于使用非最优的查询语句,不正确的索引或其他配置原因导致的。但开发人员或数据库维护人员首先要找出这些低效的查询,才能做出对应的查询优化。

MongoDB中实现慢查询的profile是非常容易,因为MongoDB内置了profile开关来记录执行时间触发了profile条件的查询。

参照db.setProfileLevel()的文档,通过以下命令就可以记录执行时长超过300ms的查询。

db.setProfilingLevel(1, 300)

当慢查询被重现后,可以通过查找system.profile collection来查看执行时长超过300ms的查询。

被profiler记录下来慢查询record看起来如下,

{
“op” : “query”, “ns” : “myCollection”, “query” : {
“builds” : {
“$elemMatch” : { “builtTime” : null, “$and” : [
{
“createdTime” : { “$lt” : ISODate(“2016-09-20T20:07:00.796Z”) } } ] } } }, “ntoreturn” : 0, “ntoskip” : 0, “nscanned” : 0, “nscannedObjects” : 18231, “keyUpdates” : 0, “writeConflicts” : 0, “numYield” : 577, “locks” : {
“Global” : {
“acquireCount” : { “r” : NumberLong(1156) } },
“Database” : {
“acquireCount” : { “r” : NumberLong(578) } },
“Collection” : { “acquireCount” : { “r” : NumberLong(578) } } }, “nreturned” : 2, “responseLength” : 98076, “millis” : 11161, “execStats” : { “stage” : “COLLSCAN”, “filter” : { “builds” : { “$elemMatch” : { “$and” : [ { “$and” : [ { “createdTime” : { “$lt” : ISODate(“2016-09-20T20:07:00.796Z”) } } ] }, { “builtTime” : { “$eq” : null } } ] } } }, “nReturned” : 2, “executionTimeMillisEstimate” : 11080, “works” : 18233, “advanced” : 2, “needTime” : 18230, “needFetch” : 0, “saveState” : 577, “restoreState” : 577, “isEOF” : 1, “invalidates” : 0, “direction” : “forward”, “docsExamined” : 18231 },
“ts” : ISODate(“2016-09-20T23:07:14.313Z”), “client” : “10.171.127.66”, “allUsers” : [ { “user” : “dbuser”, “db” : “mydb” } ], “user” : “dbuser@mydb” }

上面的数据具体解读如下,

  1. op: 'query'表示执行的是查询,
  2. ns是指查询的collection,
  3. query是具体的查询语句,
  4. 核心部分是execStats,给出了的查询语句具体执行统计,跟.explain(‘execStats’)的内容是一致的。上面的统计是说,这个query执行了整个collection的扫描(总计扫描了18231个文档),最终返回了2条文档,花费了11080ms,也就是11s还多的时间!这表明被记录下的慢查询跟collection的索引设置有问题,该查询没有用上索引。解决方案很简单,改善查询语句使用存在的索引或者设置合理的索引。
  5. ts是查询开始请求的时间,
  6. allUsersuser都是MongoDB client连接所使用的用户。