MongoDB:为什么不按多个键排序使用索引?

joh*_*odo 3 indexing mongodb mongodb-indexes

问题: 我有一个非常大的集合,按字段索引ts:(时间戳)

> db.events.ensureIndex({'ts': -1})
Run Code Online (Sandbox Code Playgroud)

我想获得最后5个条目.让我感到惊讶的是,查询不使用索引,因此非常慢:

> db.events.find().sort({'ts': -1, '_id': -1}).limit(5)
Run Code Online (Sandbox Code Playgroud)

但是,仅按ts或其他字段排序使用索引:

> db.events.find().sort({'ts': -1}).limit(5)
> db.events.find().sort({'_id': -1}).limit(5)
Run Code Online (Sandbox Code Playgroud)

这是MongoDB中的一个错误,这确实是一个记录的功能还是我做错了什么?

附加信息:

> db.events.find().sort({'ts': -1, '_id': -1}).limit(5).explain()
{
    "cursor" : "BasicCursor",
    "nscanned" : 795609,
    "nscannedObjects" : 795609,
    "n" : 5,
    "scanAndOrder" : true,
    "millis" : 22866,
    "nYields" : 73,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {

    }
}
> db.events.find().sort({'ts': -1}).limit(5).explain()
{
    "cursor" : "BtreeCursor ts_-1",
    "nscanned" : 5,
    "nscannedObjects" : 5,
    "n" : 5,
    "millis" : 0,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {
            "ts" : [
                    [
                            {
                                    "$maxElement" : 1
                            },
                            {
                                    "$minElement" : 1
                            }
                    ]
            ]
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*nie 5

值得阅读Indexing Advice&FAQ维基页面的索引策略部分.

您可能会遗漏一些注意事项:

  • MongoDB每个查询只使用一个索引

  • 使用的sort列必须是索引中的最后一列

因此,对于您的示例,您应该在ts和上添加复合索引_id:

db.events.ensureIndex({'ts': - 1,'_ id': - 1});

..并确认explain()排序现在使用预期的索引:

> db.events.find().sort({'ts': -1, '_id':-1}).limit(5).explain()
{
    "cursor" : "BtreeCursor ts_-1__id_-1",
    "nscanned" : 5,
    "nscannedObjects" : 5,
    "n" : 5,
    "millis" : 0,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {
        "ts" : [
            [
                {
                    "$maxElement" : 1
                },
                {
                    "$minElement" : 1
                }
            ]
        ],
        "_id" : [
            [
                {
                    "$maxElement" : 1
                },
                {
                    "$minElement" : 1
                }
            ]
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)