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

3

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

{
    "_id" : {
       "user" : 14197,
       "date" : ISODate("2014-10-24T00:00:00.000Z")
    },
...
}

当我尝试通过用户和日期范围选择数据时,我遇到了性能问题。MongoDB没有使用索引并在集合上运行完全扫描。

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个回答

1
TL;DR: 不要将数据放在 _id 字段中,使用 复合索引db.timeuse.daily.ensureIndex( { "user" : 1, "date": 1 } )
解释: 你滥用了 _id 键约定,或更准确地说是 MongoDB 可以索引整个对象的事实。你想要实现的目标需要索引交集或复合索引,即可以组合的两个单独的索引(该功能称为 索引交集,现在应该在 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基本上对整个对象进行了哈希处理,并且只是在查找对象哈希值 - 这样的索引无法支持基于哈希的某个部分的范围查询。

我添加了复合索引: db.timeuse.daily.ensureIndex( { "_id.user": 1, "_id.date": 11 }) - Alex Zaporozhets

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接