我在数据库中有以下结构:
{
"_id" : {
"user" : 14197,
"date" : ISODate("2014-10-24T00:00:00.000Z")
},
...
}
当我尝试按用户选择数据时出现性能问题。日期范围。 Monogo没有使用index&运行全扫描收集。
db.timeuse.daily.find({ "_id.user": 289006, "_id.date" : {$gt: ISODate("2014-10-23T00:00:00Z"), $lte: ISODate("2014-10-30T00:00:00Z")}}).explain()
{
"cursor" : "BasicCursor",
"isMultiKey" : false,
"n" : 6,
"nscannedObjects" : 66967,
"nscanned" : 66967,
"nscannedObjectsAllPlans" : 66967,
"nscannedAllPlans" : 66967,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 523,
"nChunkSkips" : 0,
"millis" : 1392,
"server" : "mongo-shard0003:27018",
"filterSet" : false,
"stats" : {
"type" : "COLLSCAN",
"works" : 66969,
"yields" : 523,
"unyields" : 523,
"invalidates" : 16,
"advanced" : 6,
"needTime" : 66962,
"needFetch" : 0,
"isEOF" : 1,
"docsTested" : 66967,
"children" : [ ]
},
"millis" : 1392
}
到目前为止,我发现只有一种方法 - 使用$ in。
db.timeuse.daily.find({"_id": { $in: [
{"user": 289006, "date": ISODate("2014-10-23T00:00:00Z")},
{"user": 289006, "date": ISODate("2014-10-24T00:00:00Z")}
]}}).explain()
{
"cursor" : "BtreeCursor _id_",
"isMultiKey" : false,
"n" : 2,
"nscannedObjects" : 2,
"nscanned" : 2,
"nscannedObjectsAllPlans" : 2,
"nscannedAllPlans" : 2,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"_id" : [
[
{
"user" : 289006,
"date" : ISODate("2014-10-23T00:00:00Z")
},
{
"user" : 289006,
"date" : ISODate("2014-10-23T00:00:00Z")
}
],
[
{
"user" : 289006,
"date" : ISODate("2014-10-24T00:00:00Z")
},
{
"user" : 289006,
"date" : ISODate("2014-10-24T00:00:00Z")
}
]
]
},
如果有更优雅的方式来运行此类查询?
答案 0 :(得分:1)
TL; DR:不要将您的数据放在_id
字段中并使用compound index:db.timeuse.daily.ensureIndex( { "user" : 1, "date": 1 } )
。
说明:
您正在滥用_id
密钥约定,或者更确切地说是MongoDB可以索引整个对象的事实。您想要实现的目标需要索引交集或复合索引,即可以组合的两个单独索引(该功能称为index intersection,到目前为止,它应该可用于MongoDB,但它有限制)或一组特殊的索引,在MongoDB中被称为复合索引。
_id
字段默认为索引编制,但它作为一个整体编制索引,即 _id
索引,只对整个对象提供支持等式查询而不是对象的一部分。这也解释了为什么$in
查询有效。
通常,具有默认索引的数据结构将表现得很奇怪。考虑一下:
> db.sort.insert({"_id" : {"name" : "foo", value : 1} });
> db.sort.insert({"_id" : {"name" : "foo", value : 1, bla : "foo"} });
> db.sort.find();
{ "_id" : { "name" : "foo", "value" : 4343 } }
{ "_id" : { "name" : "foo", "value" : 4343, "bla" : "fooffo" } }
> db.sort.find({"_id" : {"name" : "foo", value : 4343} });
{ "_id" : { "name" : "foo", "value" : 4343 } }
// no second result here...
想象一下,MongoDB基本上是对整个对象进行哈希处理,而只是查找对象哈希 - 这样的索引不能支持基于哈希部分的范围查询。