在MongoDB上限集合

时间:2016-07-31 23:33:10

标签: mongodb

我有一个带有以下索引的MongoDB上限集合:

[
    {
        "v" : 1,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "events.messageIn"
    },
    {
        "v" : 1,
        "key" : {
            "uuid" : 1,
            "ts" : -1
        },
        "name" : "uuid_1_ts_-1",
        "ns" : "events.messageIn",
        "background" : true
    }
]

正如您可能推断的那样,这是一组事件数据。由于时间戳始终在增加,因此订单{$natural: -1}应与订单{ts: -1}等效。我偶然在ts添加了一个索引,以便能够对时间片进行有效查询(例如db.messageIn.find({ts: {$gte: ISODate("2016-08-01")}})

然而,我(或许是天真地)期望db.messageIn.find({uuid: SOME_UUID}).sort({$natural: -1})能够最有效地回答逻辑问题“给我一些最新的消息”。实际上,该查询是一个集合扫描,比db.event.find({uuid: SOME_UUID}).sort({ts: -1})的计划慢几个数量级。

为什么会这样?推测性地,我假设这是因为MongoDB认为,一旦它在查看索引,它将无法提供自然顺序;结果,它回归到集合扫描。对于这个查询,MongoDB是否有一些方法可以更聪明?例如,使用书籍索引的类比:

uuid     ts                page
abcdef   2016-06-01T00:03  10
abcdef   2016-06-01T00:02  8
abcdef   2016-06-01T00:01  6
ghijkl   2016-06-01T00:03  9
mnopqr   2016-06-01T00:02  7
mnopqr   2016-06-01T00:01  5

uuid过滤后,您可以轻松按页面排序;没有必要按顺序访问每个页面,检查其uuid,并在页面匹配时生成页面。 MongoDB的“页面”引用是否以某种方式不可订购?很明显,我的心理模型在某处不足。

1 个答案:

答案 0 :(得分:0)

根据我对the documentation的理解,支持更高的插入吞吐量上限集合,不要使用索引按插入顺序(或向后插入顺序)返回文档。因此,当执行db.messageIn.find({uuid: SOME_UUID}).sort({$natural: -1})时,将逐个检查每个文档以保留插入顺序并过滤匹配文档。

另一方面,db.event.find({uuid: SOME_UUID}).sort({ts: -1})要快得多,因为它使用" uuid_1_ts_-1"匹配uuid和排序的索引。在MongoDB中,排序操作可以通过根据索引中的排序检索文档来获取排序顺序(documentation描述的案例与您的案例相似)。

顺便说一下," uuid_1_ts_-1"不会在db.messageIn.find({ts: {$gte: ISODate("2016-08-01")}})之类的查询中使用,因为它是复合索引,对于复合索引,MongoDB只能使用the index prefixes来支持查询。