В моей коллекции 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%)
- возраст пользователя соответствует указанному фильтру (одно из необязательных значений в запросе)