为聚合框架创建覆盖索引

时间:2014-02-28 09:40:11

标签: mongodb indexing aggregation-framework

我在为查询创建索引时遇到问题,但在网络上找不到任何类似的解决方案,所以也许有些人会帮助我。

为了简化问题,我们假设我们的手机有一些属性,

{
  "type":"Samsung",
  "model":"S3",
  "attributes":[{
     "value":"100",
     "name":"BatteryLife"
   },{
     "value":"200$",
     "name":"Price"
   }
}

使用index:{“type”:1,“attributes.value”:1}

我们每种类型都有数百万部手机,我想找到具有属性的给定类型的手机,我的查询如下:

db.Phone.aggregate([ 
{ "$match" : { "type" : "Samsung"}} , 
{ "$match" : { "attributes" : { "$all" : [ 
    { "value" : "100", "name" : "BatteryLife" } , 
    { "value" : "200$", "name" : "Price"}
                              ]}
             }
 }
])

它有效! 问题是这个查询非常低效,因为它只使用我的索引的第一部分,即“类型”(我有各种类型的数百万部电话),并且不使用'attributes.value'部分(类型) + attributes.value几乎是唯一的,因此它会显着降低复杂性。)

@Edit 感谢Neil Lunn我知道这是因为索引仅在我的第一场比赛中使用,所以我必须更改我的查询。

@ EDIT2 我想我找到了解决方案:

db.Phone.aggregate([
{$match: {
    $and: [ 
        {type: "Samsung"}, 
        {attributes: {
           $all: [
                { "value":"100", "type" : "BatteryLife" },
                { "value":"200$", "type" : "Price" }
           ] 
        }}
    ]}
}])

+ db.Phone.ensureIndex({type:1,attributes:1})似乎有效。我想我们现在可以关闭了。感谢关于$ match的提示。

1 个答案:

答案 0 :(得分:0)

要充分利用索引,您需要在使用索引中所有字段的管道中尽早获得$ match。并且避免使用$and运算符,因为它是不必要的,并且在当前(2.4)版本中可能导致索引无法被充分利用(幸运地为即将到来的2.6修复)。

但是,查询不太正确,因为您需要使用$elemMatch来确保使用相同的元素来满足名称和值字段。

您的查询应该是:

db.Phone.aggregate([
{$match: {  type: "Samsung", 
           attributes: { $all: [
                {$elemMatch: {"value":"100", "type" : "BatteryLife" }},
                {$elemMatch: {"value":"200$", "type" : "Price" }}
           ] }
        }
}]);

现在,它的不是将成为一个被覆盖的查询,因为嵌入了attributes.value和name,更不用说名称不在索引中了。

您需要索引为{"type":1, "attributes.value":1, "attributes.name":1}以获得最佳效果,但仍然无法覆盖,它会比现在更具选择性。