$ sort делает мой запрос слишком медленным в MongoDB - PullRequest
0 голосов
/ 25 августа 2018

У меня такой запрос, я хочу отсортировать результаты по дате.У меня есть нисходящий индекс для DateTime и восходящий индекс для UserId, но когда я пытаюсь отсортировать результат по DateTime, он становится слишком медленным.

db.Users.aggregate([  
  { "$match" : { "UserId" : { "$in" : [NUUID("1b029f8b-a17e-3172-9247- 
                  9cddfaf9702b")] } } },       
  { "$match" : { "DateTime" : { "$gte" : ISODate("2018-08-15T12:54:38Z"), 
    "$lte" : ISODate("2018-08-25T12:54:38Z") } } },   
  { "$sort" : { "DateTime" : -1} }, { "$skip" : 0 }, { "$limit" : 20 }])

, когда я удаляю часть сортировки, она становится слишком быстрой.Я попробовал, как показано ниже, и это тоже было слишком быстро.

db.Users.aggregate([             
  { "$match" : { "DateTime" : { "$gte" : ISODate("2018-08-15T12:54:38Z"), 
    "$lte" : ISODate("2018-08-25T12:54:38Z") } } }, 
  { "$match" : { "UserId" : { "$in" : [NUUID("1b029f8b-a17e-3172-9247- 
     9cddfaf9702b")] } } },  
  { "$sort" : { "UserId" : 1} },{ "$skip" : 0 }, { "$limit" : 20 }])

Почему это медленно, только когда я хочу отсортировать его по DateTime?Это структура моего документа

{
    "_id" : NUUID("11111111-1111-1111-1111-629f7992f895"),
    "DateTime" : ISODate("2018-08-23T15:49:51.153Z"),
    "UserId" : NUUID("aaaaaaaa-aaaa-aaaa-9247-9cddfaf9702b"),
    "PostId" : NUUID("bbbbbbbb-bbbb-bbbb-9529-d49ae48b2604"),
    "Type" : 3
}

Ответы [ 3 ]

0 голосов
/ 25 августа 2018

Добавьте индекс для свойств, которые вы используете в своем запросе.

Mongo нужен индекс для эффективной сортировки или сопоставления данных по заданному свойству. Без этого Монго должен посетить каждый документ в коллекции, чтобы проверить стоимость указанного свойства.

В вашем случае вы хотите убедиться, что у вас есть индекс UserId и DateTime для этой агрегации.

Поскольку у вас есть PostId, который, как я полагаю, вы используете для выполнения запросов, вам также следует добавить индекс для него.

Вы также можете посмотреть на составные индексы => https://docs.mongodb.com/manual/core/index-compound.

0 голосов
/ 27 августа 2018

Проблема производительности вашего первого запроса заключается в том, что вы создали отдельные индексы для DateTime (по убыванию) и UserId (по возрастанию). MongoDB (как в 4.0) не может использовать пересечение индекса для сортировки результатов запроса, когда операция сортировки полностью отделена от предиката, поэтому, если это единственные доступные индексы-кандидаты, можно выбрать только один.

Примечание: хотя у вас есть два $match этапа в исходном конвейере, сервер MongoDB объединит их в один $match этап , который является эквивалентным запросом с использованием $and.

Почему это медленно, только когда я хочу отсортировать его по DateTime?

Сортировка результатов в памяти считается дорогостоящей операцией, и существует предел памяти на этапе агрегирования (100 МБ) , который нельзя превысить, если вы не добавите параметр allowDiskUse в ваша агрегация. Как и в MongoDB 4.0, планировщик запросов не имеет статистических данных о количестве элементов индекса, поэтому агрегация будет отдавать предпочтение плану индекса, поддерживающему эффективную сортировку (в вашем случае это DateTime). Результатом вашего первого запроса будет сканирование индекса, чтобы найти все соответствующие значения DateTime (в отсортированном порядке), а также сравнение с каждым соответствующим документом с критериями UserId.

Во втором запросе, отсортированном по UserId, индекс UserId может использоваться как для сопоставления, так и для результатов сортировки. Результаты по-прежнему необходимо фильтровать для DateTime, но критерии UserId, вероятно, гораздо более избирательны, поэтому документов для сканирования меньше.

Идеальным индексом для поддержки обоих запросов будет составной индекс, включающий в себя DateTime и UserId, поддерживающие желаемый порядок сортировки. Например: db.Users.createIndex({ UserId: 1, DateTime: -1}). Если вы добавите этот составной индекс, вы также можете удалить исходный индекс { UserId:1}, поскольку префикс составного индекса может эффективно отвечать на те же запросы.

Самый простой способ понять производительность запроса - это explain запрос агрегации с executionStats. Для конвейеров агрегации этот уровень детализации требует MongoDB 3.6+; для более старых версий сервера вы можете объяснить эквивалентный запрос find(). Ваш запрос агрегации в настоящее время не содержит этапов обработки, которые не могут быть выражены в стандартном find() запросе.

Для получения дополнительной информации см. Использование индексов для сортировки результатов запроса в документации MongoDB. В блоге Оптимизация составных индексов MongoDB также есть некоторые полезные сведения (несмотря на использование выходных данных объяснения из более старой версии MongoDB).

0 голосов
/ 25 августа 2018

Потому что по умолчанию MongoDb создает уникальный индекс в поле _id, который используется при сортировке fast => { "UserId" : 1}.

Добавление индекса на DateTime должно помочь в увеличении скорости.

Вот некоторые соображения, касающиеся сортировки полей .

...