未使用日期的嵌入式文档索引



我是使用MongoDB的新手,我有这种类型的文档的集合:

{
"_id" : {
    "coordinate" : {
        "latitude" : 532144,
        "longitude" : -33333
    },
    "margin" : "N"
},
"prices" : [ 
    {
        "type" : "GAS_95",
        "price" : 1370,
        "date" : ISODate("2014-05-03T18:39:13.635Z")
    }, 
    {
        "type" : "DIESEL_A",
        "price" : 1299,
        "date" : ISODate("2014-05-03T18:39:13.635Z")
    }, 
    {
        "type" : "DIESEL_A_NEW",
        "price" : 1350,
        "date" : ISODate("2014-05-03T18:39:13.635Z")
    }, 
    {
        "type" : "GAS_98",
        "price" : 1470,
        "date" : ISODate("2014-05-03T18:39:13.635Z")
    }
]

}

我需要检索特定日期的价格,所以我运行这个查询:

db.gasStation.aggregate(
{ "$unwind" : "$prices"}, 
{ "$match" : { 
    "_id" : { 
        "coordinate" : { 
            "latitude" : 532144 , 
            "longitude" : -33333} , 
            "margin" : "N"
        } , 
    "prices.date" : { 
        "$gte" : ISODate("2014-05-02T23:00:00.000Z") , 
        "$lte" : ISODate("2014-05-03T22:59:59.999Z")
    }
}

});

一切都很好,我检索文档,但我认为我可以改进,我试图为_id和prices.date创建索引:

db.gasStation.ensureIndex( { 
    "_id" : 1,
    "prices.date" : 1
} )

之后,我试着看看索引是否在我的查询中使用了解释选项,但没有使用任何索引:

{
"stages" : [
    {
        "$cursor" : {
            "query" : {
            },
            "plan" : {
                "cursor" : "BasicCursor",
                "isMultiKey" : false,
                "scanAndOrder" : false,
                "allPlans" : [
                    {
                        "cursor" : "BasicCursor",
                        "isMultiKey" : false,
                        "scanAndOrder" : false
                    }
                ]
            }
        }
    },
    {
        "$unwind" : "$prices"
    },
    {
        "$match" : {
            "_id" : {
                "coordinate" : {
                    "latitude" : 532144,
                    "longitude" : -33333
                },
                "margin" : "N"
            },
            "prices.date" : {
                "$gte" : ISODate("2014-05-02T23:00:00Z"),
                "$lte" : ISODate("2014-05-03T22:59:59.999Z")
            }
        }
    }
],
"ok" : 1

}

是否有任何原因导致我的查询不适合使用索引?我在MongoDB文档中读到,唯一不使用索引的管道是$group,但我不使用该功能。

尝试重新安排您的聚合管道操作符。例如,这个查询:

db.gasStation.aggregate([
{ "$match" : {
    "_id" : {
        "coordinate" : {
            "latitude" : 532144 ,
            "longitude" : -33333} ,
            "margin" : "N"
        }
}},
{ "$unwind" : "$prices"},
{ "$match" : {
    "prices.date" : {
        "$gte" : ISODate("2014-05-02T23:00:00.000Z") ,
        "$lte" : ISODate("2014-05-03T22:59:59.999Z")
    }
}}
], {explain:true});

产生以下输出,它现在确实显示了一些索引的使用情况:

{
    "stages" : [
        {
            "$cursor" : {
                "query" : {
                    "_id" : {
                        "coordinate" : {
                            "latitude" : 532144,
                            "longitude" : -33333
                        },
                        "margin" : "N"
                    }
                },
                "plan" : {
                    "cursor" : "IDCursor",
                    "indexBounds" : {
                        "_id" : [
                            [
                                {
                                    "coordinate" : {
                                        "latitude" : 532144,
                                        "longitude" : -33333
                                    },
                                    "margin" : "N"
                                },
                                {
                                    "coordinate" : {
                                        "latitude" : 532144,
                                        "longitude" : -33333
                                    },
                                    "margin" : "N"
                                }
                            ]
                        ]
                    }
                }
            }
        },
        {
            "$unwind" : "$prices"
        },
        {
            "$match" : {
                "prices.date" : {
                    "$gte" : ISODate("2014-05-02T23:00:00Z"),
                    "$lte" : ISODate("2014-05-03T22:59:59.999Z")
                }
            }
        }
    ],
    "ok" : 1

关键是要尝试在管道开始时让管道操作符(如$match和$sort)使用索引来限制访问和传递到聚合其余部分的数据量。在上面的例子中,你可以做更多的事情来提高性能,但这应该给你一个很好的想法,如何接近它。

我将引用文档:

$match和$sort管道操作符可以利用索引当它们出现在管道的开头时。

来源:http://docs.mongodb.org/manual/core/aggregation-pipeline/pipeline-operators-and-indexes

你没有$match或$sort在管道的开始,你有$unwind操作。因此,索引在这里是无用的。

编辑 -详细说明:

仍然可以将匹配条件的一部分移动到管道的开头,以便使用索引。

db.gasStation.aggregate([
    { "$match" : {
        "_id" : {
            "coordinate" : {
                "latitude" : 532144 ,
                "longitude" : -33333} ,
                "margin" : "N"
            }
    }},
    { "$project": { "prices"  : 1, "_id" : 0 } },
    { "$unwind" : "$prices"},
    { "$match" : {
        "prices.date" : {
            "$gte" : ISODate("2014-05-02T23:00:00.000Z") ,
            "$lte" : ISODate("2014-05-03T22:59:59.999Z")
        }
    }}  
],{explain:true});

但是,这里这个索引是不必要的:

{"_id":1, "prices.date":1}

为什么?因为管道开头的$match只过滤_id。在mongodb中,文档的_id是自动索引的,这是将在这种情况下使用的索引。

此外,您可以通过使用$project操作符删除不必要的字段来进一步优化查询。如果您不需要某个字段,请尽快删除它。

相关内容

  • 没有找到相关文章

最新更新