MongoDBクエリー最適化分析

18299 ワード

要約:
MySQLでは、スロー・クエリー・ログがクエリーの最適化の根拠としてよく使われていますが、MongoDBでは似たような機能がありますか?答えは肯定的です.それはProfiling機能をオンにすることです.このツールは、実行されたインスタンスでMongoDBに関する書き込み操作、カーソル、データベースコマンドなどを収集し、データベース・レベルでツールを開くことも、インスタンス・レベルで開くこともできます.ツールは、収集されたすべてをsystem.profileセットに書き込みます.このセットはcapped collectionです.詳細については、http://docs.mongodb.org/manual/tutorial/manage-the-database-profiler/を参照してください.
使用方法:
1:Profilingレベルの説明
0:  ,       。
1:       ,   1002

2:プロファイルと設定をオンにする
1:  mongo shell:
#
drug:PRIMARY> db.getProfilingStatus()  
{ "was" : 1, "slowms" : 100 }
#    
drug:PRIMARY> db.getProfilingLevel()  
1
#    
drug:PRIMARY> db.setProfilingLevel(2)
{ "was" : 1, "slowms" : 100, "ok" : 1 }
#       
drug:PRIMARY> db.setProfilingLevel(1,200)
{ "was" : 2, "slowms" : 100, "ok" : 1 }

        test      ,           ,           ,                        :
2:   mongo shell:
mongod --profile=1 --slowms=15           2 :
profile = 1
slowms = 300

3:プロファイルを閉じる
#   
drug:PRIMARY> db.setProfilingLevel(0)
{ "was" : 1, "slowms" : 200, "ok" : 1 }

4:スロー・クエリー・ログのサイズ変更
#  Profiling
drug:PRIMARY> db.setProfilingLevel(0)
{ "was" : 0, "slowms" : 200, "ok" : 1 }
#  system.profile  
drug:PRIMARY> db.system.profile.drop() true
#      system.profile  
drug:PRIMARY> db.createCollection( "system.profile", { capped: true, size:4000000 } )
{ "ok" : 1 }
#    Profiling
drug:PRIMARY> db.setProfilingLevel(1)
{ "was" : 0, "slowms" : 200, "ok" : 1 }

注意:Secondaryのシステムを変更します.Profileのサイズは、Secondaryを停止し、独立して実行してから、上記の手順を実行する必要があります.完了したら、レプリカセットへの追加を再起動します.
遅いクエリー(system.profile)の説明:
以下の例で説明するが、詳細については、http://docs.mongodb.org/manual/reference/database-profiler/を参照してください.
1:パラメータの意味
drug:PRIMARY> db.system.profile.find().pretty()
{
    "op" : "query",    #    , insert、query、update、remove、getmore、command   
    "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   1。limit(5)         ,  ntoreturn  5。  ntoreturn  0,              ,           find()         。
    "ntoskip" : 0,     #skip()        
    "nscanned" : 304,  #    
    "keyUpdates" : 0,  #       ,                       key    key B-   
    "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" : ""               #  
}

上には次のものがあります.
scanAndOrder:
scanAndOrder      , True                          :MongoDB                        。
  scanAndOrder False,MongoDB                    。 :True:      ,False:    。

moved
                      。    update           ,          ,          ,          ,              ,             .      ,    
, .
nmoved: 。 nupdated:

getmoreはgetmore操作であり、getmoreは通常、結果セットの比較的大きなクエリで発生し、最初のqueryは結果の一部を返し、後続の結果はgetmoreによって取得されます.
nscanned(スキャンされた記録数)がnreturned(結果を返す記録数)よりはるかに大きい場合は、インデックスによる記録位置決めの最適化を考慮する.responseLengthが大きすぎると、返される結果セットが大きすぎることを示します.この場合、必要なフィールドだけが必要かどうかを見ます.
2:日常的に使用するクエリー
#     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 } )

まとめ:
Profiling機能は効率に影響を与えるに違いないが、systemを使用しているため、あまり深刻ではない.記録するprofileはcapped collectionというcollectionの操作にはいくつかの制限と特徴がありますが、効率が高いので、使用時にこの機能を開くことができ、ずっと開く必要はありません.