我有一个收藏品 订单
{
"_id": "abcd",
"last_modified": ISODate("2016-01-01T00:00:00Z"),
"suborders": [
{
"suborder_id": "1",
"last_modified: ISODate("2016-01-02T00: 00: 00Z")
}, {
"suborder_id":"2",
"last_modified: ISODate("2016-01-03T00:00:00Z")
}
]
}
我在这个集合上有两个索引: { “LAST_MODIFIED”:1} {“suborders.last_modified”:1}
当我在last_modified上使用范围查询时,正确使用索引,并立即返回结果。例如查询:db.orders.find({"last_modified":{$gt:ISODate("2016-09-15"), $lt:ISODate("2016-09-16")}});
但是,当我查询suborders.last_modified时,查询执行时间太长。 eq查询:db.orders.find({"suborders.last_modified":{$gt:ISODate("2016-09-15"), $lt:ISODate("2016-09-16")}});
请帮忙调试一下。
答案 0 :(得分:1)
简短的回答是使用min和max来正确设置索引边界。关于如何进行调试,请继续阅读。
查询性能问题的一个好地方是在查询结束时附加.explain()
。我制作了一个script来生成像你这样的文档并执行你提供的查询。
我使用了mongo 3.2.9,并且两个查询都使用此设置创建的索引。但是,第二个查询返回了更多文档(大约占集合中所有文档的6%)。我怀疑那不是你的意图。
要了解发生了什么,可以考虑一下mongo shell中的一个小例子:
> db.arrayFun.insert({
orders: [
{ last_modified: ISODate("2015-01-01T00:00:00Z") },
{ last_modified: ISODate("2016-01-01T00:00:00Z") }
]
})
WriteResult({ "nInserted" : 1 })
然后在2015年5月到7月之间进行查询:
> db.arrayFun.find({"orders.last_modified": {
$gt: ISODate("2015-05-01T00:00:00Z"),
$lt: ISODate("2015-07-01T00:00:00Z")
}}, {_id: 0})
{ "orders" : [ { "last_modified" : ISODate("2015-01-01T00:00:00Z") }, { "last_modified" : ISODate("2016-01-01T00:00:00Z") } ] }
虽然数组中的任何对象在5月到7月之间都没有last_modified,但它找到了该文档。这是因为它在数组中查找一个对象,其中last_modified
大于五月,一个对象的last_modified
小于七月。这些查询cannot intersect multikey index bounds,在您的情况下发生。您可以在indexBounds
输出的explain("allPlansExecution")
字段中看到此信息,特别是下限或上限Date
中的一个将不是您指定的内容。这意味着可能需要扫描大量文档才能完成查询,具体取决于您的数据。
要查找数组中两个边界之间有last_modified
的对象,我尝试使用$elemMatch。
db.orders.find({"suborders": {
$elemMatch:{
last_modified:{
"$gt":ISODate("2016-09-15T00:00:00Z"),
"$lt":ISODate("2016-09-16T00:00:00Z")
}
}
}})
在我的测试中,这回复了约0.5%的所有文件。但是,它仍然运行缓慢。 explain
输出显示它仍未正确设置索引边界(仅使用一个边界)。
db.subDocs.find()
.min({"suborders.last_modified":ISODate("2016-09-15T00:00:00Z")})
.max({"suborders.last_modified":ISODate("2016-09-16T00:00:00Z")})
返回了与$elemMatch
相同的文档,但在索引上使用了两个边界。对于elemMatch和原始发现,它的运行时间为0.021s,而2-4s则为。