MongoDB: почему сортировка по нескольким ключам не использует индекс?

Вопрос. У меня есть очень большая коллекция, которая индексируется по полю ts: (отметка времени)

> db.events.ensureIndex({'ts': -1})

Я хочу получить последние 5 записей. Что меня удивляет, так это то, что запрос не использует индекс и поэтому очень медленный:

> db.events.find().sort({'ts': -1, '_id': -1}).limit(5)

Однако сортировка только по ts или другому полю использует индекс, как и должно быть:

> db.events.find().sort({'ts': -1}).limit(5)
> db.events.find().sort({'_id': -1}).limit(5)

Это ошибка в 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
                            }
                    ]
            ]
    }
}

person johndodo    schedule 22.08.2012    source источник


Ответы (1)


Стоит прочитать раздел Стратегии индексирования в Совете по индексированию. и вики-страница часто задаваемых вопросов.

Есть несколько соображений, которые вы можете упустить:

  • 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
                }
            ]
        ]
    }
}
person Stennie    schedule 22.08.2012
comment
Это действительно ответ - думаю, реляционные БД меня избаловали... :) Спасибо! - person johndodo; 22.08.2012
comment
Почему столбец сортировки должен быть последним столбцом в индексе? - person user4951; 11.09.2012