Неоправданно медленный запрос MongoDB, даже если запрос прост и выровнен по индексам - PullRequest
12 голосов
/ 24 ноября 2011

Я использую сервер 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 «привязка» сбрасывается. Эта настройка допускает работу с документами с предыдущих страниц, для которых значение LastUpdated было изменено, т. Е. Подкачка не будет неправильно смещена из-за количества документов на предыдущих страницах, которых технически больше нет на этих страницах.

Проблема

В идеале я хочу выбрать около 25000 документов за раз, но по какой-то причине сам запрос (даже при выборе <500 документов) <em>крайне медленный.

Я выполнил запрос:

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 минут и еще не завершено. Я обновлю этот вопрос, если он когда-нибудь закончится, но суть в том, что запрос является ОЧЕНЬ медленным.

Что я могу сделать? У меня нет ни малейшего понятия, в чем проблема с запросом.

EDIT Объяснение закончилось через 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",
                            {

                            }
                    ]
            ]
    }
}

Ответы [ 3 ]

12 голосов
/ 24 января 2012

Столкнулся с очень похожей проблемой, и Советы по индексированию и часто задаваемые вопросы на Mongodb.org говорят, цитата:

Запрос диапазона также должен быть последним столбцом в индексе

Так что, если у вас есть ключи a, b и c и вы запускаете db.ensureIndex ({a: 1, b: 1, c: 1}), это «рекомендации» для того, чтобы максимально использовать индекс :

Хорошо:

  • найти (а = 1, Ь> 2)

  • найти (а> 1 и а <10) </p>

  • find (a> 1 и a <10) .sort (a) </p>

Bad:

  • найти (a> 1, b = 2)

Используйте только запрос диапазона ИЛИ сортировать только по одному столбцу. Хорошо:

  • найти (a = 1, b> 2 и b <4) </p>

Bad:

  • найти (а> 1, Ь> 2)

Надеюсь, это поможет!

* * Тысяча шестьдесят-восемь / J
7 голосов
/ 24 ноября 2011

Хорошо, я решил это. Виновником был "scanAndOrder": true, что указывало на то, что индекс использовался не по назначению. Правильный составной индекс имеет первичное поле сортировки, а затем запрашиваемые поля.

{ "_id":1, "LastUpdated":1 }
0 голосов
/ 24 ноября 2011

Вы пытались добавить _id к вашему составному индексу. Поскольку вы используете его как часть запроса, не придется ли ему выполнять полное сканирование таблицы?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...