执行计划及慢查询

explain执行计划

MongoDB 提供了一个 explain 命令让我们获知系统如何处理查询请求。利用 explain 命令,我们可以很好地观察系统如何使用索引来加快检索,同时可以针对性优化索引。

MongoDB Enterprise myrepl:PRIMARY> db.foo.find({"a":3000}).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test.foo",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "a" : {
                "$eq" : 3000
            }
        },
        "winningPlan" : {
            "stage" : "COLLSCAN",
            "filter" : {
                "a" : {
                    "$eq" : 3000
                }
            },
            "direction" : "forward"
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "mydb1",
        "port" : 27017,
        "version" : "3.4.20",
        "gitVersion" : "447847d93d6e0a21b018d5df45528e815c7c13d8"
    },
    "ok" : 1
}
MongoDB Enterprise myrepl:PRIMARY> db.foo.find({"a":3000}).explain("executionStats")
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test.foo",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "a" : {
                "$eq" : 3000
            }
        },
        "winningPlan" : {
            "stage" : "COLLSCAN",
            "filter" : {
                "a" : {
                    "$eq" : 3000
                }
            },
            "direction" : "forward"
        },
        "rejectedPlans" : [ ]
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 1,
        "executionTimeMillis" : 0,
        "totalKeysExamined" : 0,
        "totalDocsExamined" : 1002,
        "executionStages" : {
            "stage" : "COLLSCAN",
            "filter" : {
                "a" : {
                    "$eq" : 3000
                }
            },
            "nReturned" : 1,
            "executionTimeMillisEstimate" : 0,
            "works" : 1004,
            "advanced" : 1,
            "needTime" : 1002,
            "needYield" : 0,
            "saveState" : 7,
            "restoreState" : 7,
            "isEOF" : 1,
            "invalidates" : 0,
            "direction" : "forward",
            "docsExamined" : 1002
        }
    },
    "serverInfo" : {
        "host" : "mydb1",
        "port" : 27017,
        "version" : "3.4.20",
        "gitVersion" : "447847d93d6e0a21b018d5df45528e815c7c13d8"
    },
    "ok" : 1
}

"stage" : "IXSCAN",稍好一些

还要看nReturnedtotalDocsExaminedtotalKeysExamined

对于普通查询,我希望看到stage的组合(查询的时候尽可能用上索引)

Fetch+IDHACK

Fetch+ixscan

Limit+Fetch+ixscan

PROJECTION+ixscan

SHARDING_FITER+ixscan

COUNT_SCAN

不希望看到包含如下的stage

COLLSCAN(全表扫描),SORT(使用sort但是无index),不合理的SKIP,SUBPLA(未用到index$or),COUNTSCAN(不使用index进行count)

https://www.cnblogs.com/c-abc/p/6023824.html

http://www.mongoing.com/eshu_explain1

使用profiler

Mongo profile类似于MySQLslow log, MongoDB可以监控所有慢的以及不慢的查询。

Profiler默认是关闭的,你可以选择全部开启,或者有慢查询的时候开启。

Profiling级别说明

0:关闭,不收集任何数据。

1:收集慢查询数据,默认是100毫秒。

2:收集所有数据

查看状态:级别和时间

myrepl:PRIMARY> db.getProfilingStatus()

{ "was" : 1, "slowms" : 100 }

查看级别

myrepl:PRIMARY> db.getProfilingLevel()

1

设置级别

myrepl:PRIMARY> db.setProfilingLevel(2)

{ "was" : 1, "slowms" : 100, "ok" : 1 }

设置级别和时间

myrepl:PRIMARY> db.setProfilingLevel(1,500)

{ "was" : 2, "slowms" : 500, "ok" : 1 }

关闭

myrepl:PRIMARY> db.setProfilingLevel(0)

{ "was" : 1, "slowms" : 500, "ok" : 1 }

myrepl:PRIMARY> use local

myrepl:PRIMARY> db.system.profile.find().pretty()

{

    "op" : "query",    #操作类型,有insertqueryupdateremovegetmorecommand   

    "ns" : "mc.user",  #操作的集合

    "query" : {        #查询语句

        "mp_id" : 5,

        "is_fans" : 1,

        "latestTime" : {

            "$ne" : 0

        },

        "latestMsgId" : {

            "$gt" : 0

        },

        "$where" : "new Date(this.latestNormalTime)>new Date(this.replyTime)"

    },

    "cursorid" : NumberLong("1475423943124458998"),

    "ntoreturn" : 0,   #返回的记录数。例如,profile命令将返回一个文档(一个结果文件),因此ntoreturn值将为1limit(5)命令将返回五个文件,因此ntoreturn值是5。如果ntoreturn值为0,则该命令没有指定一些文件返回,因为会是这样一个简单的find()命令没有指定的限制。

    "ntoskip" : 0,     #skip()方法指定的跳跃数

    "nscanned" : 304,  #扫描数量

    "keyUpdates" : 0,  #索引更新的数量,改变一个索引键带有一个小的性能开销,因为数据库必须删除旧的key,并插入一个新的keyB-树索引

    "numYield" : 0,    #该查询为其他查询让出锁的次数

    "lockStats" : {    #锁信息,R:全局读锁;W:全局写锁;r:特定数据库的读锁;w:特定数据库的写锁

        "timeLockedMicros" : {     #

            "r" : NumberLong(19467),

            "w" : NumberLong(0)

        },

        "timeAcquiringMicros" : {  #锁等待

            "r" : NumberLong(7),

            "w" : NumberLong(9)

        }

    },

    "nreturned" : 101,        #返回的数量

    "responseLength" : 74659, #响应字节长度

    "millis" : 19,            #消耗的时间(毫秒)

    "ts" : ISODate("2014-02-25T02:13:54.899Z"), #语句执行的时间

    "client" : "127.0.0.1",   #链接ip或则主机

    "allUsers" : [ ],     

    "user" : ""               #用户

}

日常使用的查询

#返回最近的10条记录

db.system.profile.find().limit(10).sort({ ts : -1 }).pretty()

#返回所有的操作,除command类型的

db.system.profile.find( { op: { $ne : 'command' } } ).pretty()

#返回特定集合

db.system.profile.find( { ns : 'mydb.test' } ).pretty()

#返回大于5毫秒慢的操作

db.system.profile.find( { millis : { $gt : 5 } } ).pretty()

#从一个特定的时间范围内返回信息

db.system.profile.find(

                       {

                        ts : {

                              $gt : new ISODate("2012-12-09T03:00:00Z") ,

                              $lt : new ISODate("2012-12-09T03:40:00Z")

                             }

                       }

                      ).pretty()

#特定时间,限制用户,按照消耗时间排序

db.system.profile.find(

                       {

                         ts : {

                               $gt : new ISODate("2011-07-12T03:00:00Z") ,

                               $lt : new ISODate("2011-07-12T03:40:00Z")

                              }

                       },

                       { user : 0 }

                      ).sort( { millis : -1 } )

原文地址:https://www.cnblogs.com/allenhu320/p/11340088.html