Сократить время выполнения запроса в MongoDB при запросе тегов в массиве - PullRequest
1 голос
/ 12 марта 2020

В моей коллекции MongoDB (одной из многих) в настоящее время хранится более 30 миллионов документов общим объемом 40 ГБ. Ожидается, что он достигнет более 100 миллионов записей. Я обеспокоен тем, что предел оперативной памяти будет достигнут в ближайшее время, и мы должны будем изучить шардеры или другие методы. Иногда документы требуют последующей обработки языком программирования (в данном случае Python).

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

Коллекция имеет составной индекс, а документы индексируются по:

  • массив тегов (обязательно для запроса)
  • 4-5 необязательных полей с одним значением (которые при использовании ускоряют выполнение)

Мое беспокойство является то, что теги могут быть недостаточно селективными. Каждый документ может содержать от 5 до 25 тегов. Существуют сотни комбинаций тегов, которые, как я думал, могут сделать запросы намного более эффективными, чем они есть на самом деле.

Статистика выполнения только по тегам показывает очень медленный запрос:

 "executionStats" : {
                "executionSuccess" : true,
                "nReturned" : 3737324,
                "executionTimeMillis" : 22600,
                "totalKeysExamined" : 3737324,
                "totalDocsExamined" : 3737324,

Этап ввода подтверждает, что индекс использовался:

"inputStage" : {
                                "stage" : "IXSCAN",
                                "nReturned" : 3737324,
                                "executionTimeMillisEstimate" : 954,
                                "works" : 3737325,
                                "advanced" : 3737324,
                                "needTime" : 0,
                                "needYield" : 0,
                                "saveState" : 29199,
                                "restoreState" : 29199,
                                "isEOF" : 1,

, но результаты все еще неудовлетворительные.

Шаги, предпринятые для уменьшения времени выполнения:

  • Проецируются только необходимые поля, которые сокращают время на 10-30% в зависимости от запроса
  • Пытался уменьшите размер каждого документа, чтобы он содержал только необходимые и непустые поля
  • Попытка сделать теги более избирательными

Какие еще стратегии я мог бы использовать для ускорения выполнения и попытаться получить время чтения менее 100 мс, как рекомендовано инструментом мониторинга? Вот некоторые идеи, которые у меня были:

  • Разделение тегов на отдельные, отдельные коллекции
  • Использование агрегата вместо поиска, чтобы ограничить количество возвращаемых документов, чтобы избежать последующей обработки
  • Имейте коллекцию только тегов в одной коллекции и информацию о каждом документе в другом, но это приведет к тысячам или миллионам отдельных вызовов по идентификатору в коллекцию информации

Запрос довольно прост и выглядит следующим образом:

db.collection.find({ tags: { $all: [tag1, tag2, tag3] }, optional_value: 1, optional_value: 2})

Python код анализирует все записи, возвращенные для распечатки отчетов на основе данных. Некоторые из проанализированных полей могут быть:

  • действия, предпринятые пользователем, которые соответствуют указанному фильтру
  • профиль пользователя соответствует указанному фильтру (пользователи хранятся в другой коллекции, список они, соответствующие критериям, агрегируются, и затем пользователь документа сравнивается со списком имен пользователей соответствующего профиля в коде python - здесь есть место для улучшения, хотя это только увеличивает время запроса на 10-20%)
  • возраст пользователя соответствует указанному фильтру (одно из необязательных значений в запросе)
...