2012-04-18 79 views
7

集合事件包含userId和一系列事件 - 数组中的每个元素都是嵌入式文档。例如:mongodb - 不使用日期索引

{ 
    "_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", 

}

使用如下面在过去30天内产生的一个事件找到相当的查询:

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

查询计划显示的“events.eventDate”索引时使用测试数据包含较少的事件(大约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") 
        ] 
      ] 
    } 

}

然而,当有大量的事件(约500),不使用索引:

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

    } 

}

为什么当有很多事件没有被使用的索引?可能在 有大量事件时,MongoDB发现只扫描所有项目比使用索引更有效率?

+0

你在抱怨说,优化器不会在需要0ms返回的查询上使用索引吗? :) – 2012-04-19 02:49:59

+0

上面的解释输出来自测试集合。大约20M的文件,查询大约需要8秒。 – dsatish 2012-04-19 14:15:11

+0

如果您查询集合文档的重要部分,则这样的范围查询可能会很慢。您可以使用提示来强制索引来比较速度,但我认为它会做索引扫描一样慢。您应该在生产数据中发布解释,不论有无提示。问题是,如果你找到了几百万条匹配的文件,那么检查它们需要一些时间。 – 2012-04-19 14:34:04

回答

11

MongoDB的查询优化器以特殊方式工作。它不是计算某些查询计划的成本,而是启动所有可用的计划。无论哪个返回首先被认为是最优的,并将在未来使用。

应用程序增长,数据增长和变化,最佳计划可能在某些时候变得不是最佳。所以,mongo每隔一段时间重复一遍查询选择过程。

看来,在这个具体的案例中,基本扫描是最有效的。

链接:http://www.mongodb.org/display/DOCS/Query+Optimizer

2

使用$提示强制使用索引 “events.eventDate”,该nscannedObjects比W/O型的指数多。

伪代码使用索引时:

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个用户对象仅被检查一次。因此,使用索引时,用户对象被扫描的次数多于不使用索引时的次数。这种理解是正确的吗?

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" : { 

}