Неоправданно медленный запрос MongoDB, хотя запрос прост и согласован с индексами
Я запускаю сервер MongoDB (который буквально все работает). Сервер имеет 64 ГБ оперативной памяти и 16 ядер, плюс 2 ТБ на жестком диске для работы.
Структура документа
В базе данных имеется коллекция domains
с около 20 миллионами документов. В каждом документе есть приличный объем данных, но для наших целей документ структурирован так:
{
_id: "abcxyz.com",
LastUpdated: <date>,
...
}
Поле _id - это имя домена, на которое ссылается документ. На LastUpdated есть восходящий индекс. LastUpdated обновляется сотнями тысяч записей в день. В основном каждый раз, когда новые документы становятся доступными для документа, документ обновляется, а поле LastUpdated обновляется до текущей даты/времени.
Запрос
У меня есть механизм, который извлекает данные из базы данных, поэтому его можно индексировать в индексе Lucene. Поле LastUpdated является ключевым драйвером для пометки изменений, внесенных в документ. Для поиска документов, которые были изменены, и страницы через эти документы, я делаю следующее:
{
LastUpdated: { $gte: ISODate(<firstdate>), $lt: ISODate(<lastdate>) },
_id: { $gt: <last_id_from_previous_page> }
}
sort: { $_id:1 }
Когда документы не возвращаются, даты начала и окончания перемещаются вперед, а поле _id "anchor" - reset. Эта настройка толерантна к документам с предыдущих страниц, у которых было изменено их значение LastUpdated, т.е. Пейджинг не будет неправильно смещен количеством документов на предыдущих страницах, которые теперь технически уже не находятся на этих страницах.
Проблема
Я хочу в идеале выбрать около 25000 документов за раз, но по какой-то причине сам запрос (даже при выборе только 500 документов) очень медленный.
Я выполнил запрос:
db.domains.find({
"LastUpdated" : {
"$gte" : ISODate("2011-11-22T15:01:54.851Z"),
"$lt" : ISODate("2011-11-22T17:39:48.013Z")
},
"_id" : { "$gt" : "1300broadband.com" }
}).sort({ _id:1 }).limit(50).explain()
Это так медленно, что объяснение (на момент написания этого) работает более 10 минут и еще не завершено. Я буду обновлять этот вопрос, если он когда-либо закончится, но, конечно, дело в том, что запрос ЧРЕЗВЫЧАЙНО медленный.
Что я могу сделать? Я не имею ни малейшего понятия, что проблема может быть с запросом.
ИЗМЕНИТЬ
Объяснение закончилось через 55 минут. Вот он:
{
"cursor" : "BtreeCursor Lastupdated_-1__id_1",
"nscanned" : 13112,
"nscannedObjects" : 13100,
"n" : 50,
"scanAndOrder" : true,
"millis" : 3347845,
"nYields" : 5454,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"LastUpdated" : [
[
ISODate("2011-11-22T17:39:48.013Z"),
ISODate("2011-11-22T15:01:54.851Z")
]
],
"_id" : [
[
"1300broadband.com",
{
}
]
]
}
}
Ответы
Ответ 1
Включение в очень похожую проблему, и Рекомендации по индексированию и часто задаваемые вопросы на Mongodb.org говорит, цитируйте:
Запрос диапазона также должен быть последним столбцом в индексе
Итак, если у вас есть ключи a, b и c и запустите db.ensureIndex({a: 1, b: 1, c: 1}), это "рекомендации", чтобы максимально использовать индекс
Хорошо:
Плохо:
Используйте только запрос диапазона или сортировку по одному столбцу. Хорошо:
-
найти (а = 1, B = 2).sort(с)
-
находка (а = 1, Ь > 2)
-
найти (a = 1, b > 2 и b < 4)
-
находка (а = 1, Ь > 2).sort(б)
Плохо:
Надеюсь, что это поможет!
/J
Ответ 2
Хорошо, я решил. Преступник был "scanAndOrder": true
, который предположил, что индекс не использовался по назначению. Правильный составной индекс сначала содержит первичное поле сортировки, а затем запрашиваемые поля.
{ "_id":1, "LastUpdated":1 }
Ответ 3
Вы пытались добавить _id в свой составной индекс. Поскольку вы используете его как часть запроса, ему все равно придется выполнять полное сканирование таблицы?