2013-05-09 3 views
6

postという名前のMongoDBコレクションがあり、というオブジェクトがあります。コレクションには、次のように定義された2つの2次インデックスがあります。マルチキーインデックスのクエリが遅い

> db.post.getIndexKeys() 
[ 
    { 
     "_id" : 1 
    }, 
    { 
     "namespace" : 1, 
     "domain" : 1, 
     "post_id" : 1 
    }, 
    { 
     "namespace" : 1, 
     "post_time" : 1, 
     "tags" : 1 // this is an array field 
    } 
] 

は、私は単にnamespacepost_timeによってフィルタ次のクエリは、すべてのオブジェクトをスキャンすることなく、合理的な時間内で実行することを期待します。

>db.post.find({post_time: {"$gte" : ISODate("2013-04-09T00:00:00Z"), "$lt" : ISODate("2013-04-09T01:00:00Z")}, namespace: "my_namespace"}).count() 
7408 

はしかし、それは不思議、それはexplain機能に応じて仕事をする7000万オブジェクトをスキャンするために管理し、その結果を取得するために、MongoDBの少なくとも10分かかります。

> db.post.find({post_time: {"$gte" : ISODate("2013-04-09T00:00:00Z"), "$lt" : ISODate("2013-04-09T01:00:00Z")}, namespace: "my_namespace"}).explain() 
{ 
    "cursor" : "BtreeCursor namespace_1_post_time_1_tags_1", 
    "isMultiKey" : true, 
    "n" : 7408, 
    "nscannedObjects" : 69999186, 
    "nscanned" : 69999186, 
    "nscannedObjectsAllPlans" : 69999186, 
    "nscannedAllPlans" : 69999186, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 378967, 
    "nChunkSkips" : 0, 
    "millis" : 290048, 
    "indexBounds" : { 
     "namespace" : [ 
      [ 
       "my_namespace", 
       "my_namespace" 
      ] 
     ], 
     "post_time" : [ 
      [ 
       ISODate("2013-04-09T00:00:00Z"), 
       ISODate("292278995-01--2147483647T07:12:56.808Z") 
      ] 
     ], 
     "tags" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ] 
    }, 
    "server" : "localhost:27017" 
} 

オブジェクトの数及びスキャンの数との差は、(すべての2に等しい)タグ配列の長さによって引き起こされなければなりません。それでも、私はなぜpost_timeフィルタがインデックスを利用していないのか分かりません。

私に何が欠けているか教えていただけますか?この質問に私の答えを見つけ

(私は24個のコアと96ギガバイトのRAMと下降マシンに取り組んでいます私はMongoDBの2.2.3を使用しています。。)

+0

名前空間のカーディナリティが非常に低くなっていますか? – Sammaye

+0

現在、使用している名前空間の名前空間の名前は1つだけです。 –

+0

それで、MongoDBはまず最初のフィールドを制限しなければならないので、 'my_namespace'をすべて取得してから、その日付の間にすべてのドキュメントを取得します。そうすれば、post_timeが最初になるようにインデックスを並べ替えます。 – Sammaye

答えて

3

Order of $lt and $gt in MongoDB range query

私のインデックスがマルチキーでありますindex(tags)と範囲照会(post_time)を実行しています。 の場合、MongoDBは範囲の両側をフィルタとして使用することができないので、最初に$gte句を選択するだけです。私の下限値は一番低いpost_timeなので、MongoDBはすべてのオブジェクトのスキャンを開始します。

残念ながら、これはすべての話ではありません。問題を解決しようとすると、マルチキー以外のインデックスも作成されましたが、MongoDBは悪いインデックスを使用することを主張しました。それは私が問題が他の場所にあると思うようにしました。最後に、マルチキーインデックスを削除して、tagsフィールドのないインデックスを作成する必要がありました。今はすべて大丈夫です。

+0

ダング私は '$ gt'と' $ lt'とmiltikeysについて知りませんでした。 – Sammaye

+0

cursor.hintを使用すると、mongodbが他のインデックスを使用するようにすることもできます (http://docs.mongodb.org/manual/reference/method/cursor.hint/#cursor.hint) – rudi