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-20T2000.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-20T2000.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-20T2314.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连接所使用的用户。