2012-04-18 12 views
7

コレクションイベントにはuserIdとイベントの配列があります。配列の各要素は埋め込みドキュメントです。例:mongodb - 日付のインデックスは使用されていません

db.events.find({ events : { $elemMatch: { "eventId" : 201, 
"eventDate" : {$gt : new Date(1231657163876) } } } } ).explain() 

クエリプランは、 "events.eventDate" のインデックスが時に使用されていることを示しています。過去30日間に発生したイベントtofind以下のようなクエリを使用して

{ 
    "_id" : ObjectId("4f8f48cf5f0d23945a4068ca"), 
    "events" : [ 
      { 
        "eventType" : "profile-updated", 
        "eventId" : "247266", 
        "eventDate" : ISODate("1938-04-27T23:05:51.451Z"), 
      }, 
      { 
        "eventType" : "login", 
        "eventId" : "64531", 
        "eventDate" : ISODate("1948-05-15T23:11:37.413Z"), 
      } 
    ], 
    "userId" : "junit-19568842", 

}

テストデータ(20程度)より少ないイベントが含ま:

{ 
    "cursor" : "BtreeCursor events.eventDate_1", 
    "nscanned" : 0, 
    "nscannedObjects" : 0, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : true, 
    "indexOnly" : false, 
    "indexBounds" : { 
      "events.eventDate" : [ 
        [ 
          ISODate("2009-01-11T06:59:23.876Z"), 
          ISODate("292278995-01--2147483647T07:12:56.808Z") 
        ] 
      ] 
    } 

}

012 (500周りの)イベントの数が多い場合しかし、インデックスが使用されていない

:イベントが多い場合

{ 
    "cursor" : "BasicCursor", 
    "nscanned" : 4, 
    "nscannedObjects" : 4, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 

    } 

}

はなぜインデックスが使用されていませんか? イベントが多数ある場合、MongoDBはインデックスを使用するよりもすべてのアイテムをスキャンするだけで効率的だとわかりますか?

+0

オプティマイザが0msを返すクエリでインデックスを使用しないと不平を言っていますか? :) –

+0

上記の説明出力はテストコレクションからのものです。約20Mのドキュメントでは、クエリに約8秒かかりました。 – dsatish

+0

コレクションの文書の大部分を照会している場合、そのような範囲照会は遅くなる可能性があります。ヒントを使用してインデックスと速度を比較させることもできますが、インデックススキャンを行うのと同じように遅くなると思います。ヒントの有無にかかわらず、本番データから説明を投稿する必要があります。問題は、一致する数百万もの文書が見つかった場合、文書を検査するのに時間がかかることです。 –

答えて

11

MongoDBのクエリオプティマイザは特別な方法で動作します。特定のクエリプランのコストを計算するのではなく、利用可能なすべてのプランを起動するだけです。最初に返されるものは最適なものとみなされ、将来使用されます。

アプリケーションが大きくなり、データが大きくなり、変更されると、最適なプランがある時点で最適にならないことがあります。そのため、mongoはそのクエリ選択プロセスを毎回繰り返しています。

この具体的なケースでは、基本スキャンが最も効率的でした。

リンク:インデックス "events.eventDate" を使用して強制的に$のヒントを使用してhttp://www.mongodb.org/display/DOCS/Query+Optimizer

2

、nscannedObjectsはインデックスO/W以上のものです。

擬似コード索引使用:

for(all entries in index matching the criteria) { 
    get user object and scan to see if the eventId criteria is met 
} 

条件に一致するインデックス内のすべてのエントリを - >各イベントは、インデックス内のエントリです。したがって、インデックスのエントリ数はユーザー数を上回ります。 4つのユーザーオブジェクトと基準に一致する合計7つのイベントがあるとすると、ユーザーオブジェクトは7回スキャンされます(ループは7回実行されます)。インデックスがスキャンされない場合、4つのユーザーオブジェクトはすべて1回だけ検査されます。したがって、インデックスを使用すると、ユーザオブジェクトがスキャンされる回数は、インデックスを使用しない場合よりも多くなります。これは正しいのでしょうか?

db.events.find({ events : { $elemMatch: { "eventId" : 201, 
"eventDate" : {$gt : new Date(1231657163876) } } } } ) 
._addSpecial("$hint",{"events.eventDate":1}).explain() 

{ 
    "cursor" : "BasicCursor", 
    "nscanned" : 7, 
    "nscannedObjects" : 7, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 

} 
関連する問題