MongoDB对象字段和范围查询索引

时间:2014-11-06 17:02:08

标签: mongodb mongodb-query

我在数据库中有以下结构:

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

如果有更优雅的方式来运行此类查询?

1 个答案:

答案 0 :(得分:1)

TL; DR:不要将您的数据放在_id字段中并使用compound indexdb.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基本上是对整个对象进行哈希处理,而只是查找对象哈希 - 这样的索引不能支持基于哈希部分的范围查询。