Чтение вывода explain() для диагностики запросов
Вы научитесь интерпретировать этапы IXSCAN и COLLSCAN в выводе explain и выявлять отсутствующие индексы по соотношениям nReturned и docsExamined.
«Чтение вывода explain() для диагностики запросов» — бесплатный урок MongoDB Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения MongoDB Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс MongoDB Academy содержит 4 уроков всего.
Зачем нужен explain()
Медленные запросы в MongoDB обычно возникают из-за отсутствующих индексов или неоптимальных планов запросов. Метод explain() точно показывает, что MongoDB сделала для выполнения запроса: какой индекс выбрала, сколько документов просканировала и сколько времени занял каждый этап. Без explain() настройка производительности превращается в догадки, а с ним Вы получаете точный диагностический отчёт.
// Three verbosity levels
db.users.find({ age: { $gt: 25 } }).explain(); // 'queryPlanner'
db.users.find({ age: { $gt: 25 } }).explain('executionStats'); // includes timing
db.users.find({ age: { $gt: 25 } }).explain('allPlansExecution'); // all candidate plansРежим queryPlanner
Режим explain() по умолчанию возвращает результат планировщика запросов: выигрышный план и отклонённые планы, но не выполняет сам запрос. Это быстро и удобно для беглого просмотра структуры плана. Ключевым является поле winningPlan, описывающее дерево этапов выполнения, которое использовала бы MongoDB.
const result = db.orders.find({ userId: 'u1' }).explain();
// winningPlan shows the chosen execution strategy
console.log(JSON.stringify(result.queryPlanner.winningPlan, null, 2));
// Example:
// { 'stage': 'FETCH',
// 'inputStage': {
// 'stage': 'IXSCAN',
// 'indexName': 'userId_1' } }IXSCAN и COLLSCAN
Два наиболее важных названия этапов в результате explain(): IXSCAN (просмотр индекса) — запрос использовал индекс; COLLSCAN (просмотр коллекции) — MongoDB просканировала каждый документ. COLLSCAN в рабочей коллекции с миллионами документов почти всегда означает ошибку. Наличие COLLSCAN — первый признак того, что нужно добавить или уточнить индекс.
// BAD: COLLSCAN means no usable index
// { 'stage': 'COLLSCAN', 'filter': { 'email': { '$eq': 'a@b.com' } } }
// GOOD: IXSCAN means an index was used
// { 'stage': 'IXSCAN', 'indexName': 'email_1', 'direction': 'forward' }
// Fix: create the missing index
db.users.createIndex({ email: 1 });Режим executionStats
explain('executionStats') действительно выполняет запрос и собирает данные о времени выполнения. Наиболее важные показатели: nReturned — документы, возвращённые клиенту; totalDocsExamined — документы, проверенные MongoDB; totalKeysExamined — просмотренные записи индекса. Для эффективного запроса должно выполняться условие nReturned ≈ totalDocsExamined. Большая разница указывает на напрасно выполненную работу.
const stats = db.orders
.find({ userId: 'u1', status: 'active' })
.explain('executionStats');
const s = stats.executionStats;
console.log('Returned: ', s.nReturned);
console.log('Keys Examined: ', s.totalKeysExamined);
console.log('Docs Examined: ', s.totalDocsExamined);
console.log('Execution ms: ', s.executionTimeMillis);Интерпретация ключевых соотношений
Эффективность запроса помогают оценить три соотношения: просмотренные ключи / возвращённые ключи (чем меньше, тем лучше; идеальный результат — 1:1), просмотренные документы / возвращённые документы (должно быть близко к 1) и просмотренные документы / просмотренные ключи (значение, намного превышающее 1, означает, что индекс хорошо фильтрует данные, но получение документов обходится дорого). Эти соотношения помогают понять, нужен ли Вам лучший индекс, покрывающий запрос индекс или другая стратегия фильтрации.
// Efficiency check formula
const ratio = s.totalDocsExamined / s.nReturned;
// ratio = 1 -> perfect, index is very selective
// ratio = 10 -> for every doc returned, 10 were scanned (room to improve)
// ratio = 1000+ -> strong signal to add or redesign indexЭтап FETCH
После того как IXSCAN находит подходящие записи индекса, MongoDB может потребоваться выполнить FETCH, чтобы получить сами документы с диска и проверить условия, не покрытые индексом, или вернуть поля, отсутствующие в индексе. Покрывающий запрос полностью устраняет этап FETCH. Если Вы видите IXSCAN → FETCH с высоким значением totalDocsExamined, рассмотрите возможность добавить возвращаемые поля в индекс, чтобы сделать запрос покрывающим.
// With IXSCAN only on userId, fetching to check 'status' adds FETCH
// winningPlan:
// { stage: 'FETCH',
// filter: { status: { $eq: 'active' } },
// inputStage: { stage: 'IXSCAN', indexName: 'userId_1' } }
// Fix: compound index so status is in the index too
db.orders.createIndex({ userId: 1, status: 1 });
// Now: IXSCAN only, no FETCH needed for the filterОтклонённые планы и кэш планов
Во время пробного выполнения MongoDB оценивает несколько вариантов планов параллельно и выбирает победителя на основе количества документов, возвращаемых каждым планом за единицу работы. Выигрышный план кэшируется для данной формы запроса, поэтому при следующих запусках повторная оценка не требуется. Просмотреть отклонённые планы можно с помощью уровня подробности allPlansExecution. Кэш сбрасывается при изменении индексов или существенном обновлении статистики коллекции.
// See all candidate plans and why the winner was chosen
const allPlans = db.orders
.find({ userId: 'u1', status: 'active' })
.explain('allPlansExecution');
// rejectedPlans shows what MongoDB tried but discarded
console.log(allPlans.queryPlanner.rejectedPlans.length, 'plans rejected');Этапы SORT и SORT_KEY
Если MongoDB не может использовать индекс для сортировки, она добавляет в план находящийся в памяти этап SORT. По умолчанию сортировка в памяти ограничена 100 MB; при превышении этого объёма запрос завершается ошибкой, если не включить allowDiskUse. Наличие этапа SORT указывает на необходимость добавить составной индекс, порядок ключей которого соответствует сортировке, полностью устранив сортировку в памяти.
// explain shows in-memory sort when index doesn't cover the sort order
// { stage: 'SORT', sortPattern: { createdAt: -1 },
// inputStage: { stage: 'IXSCAN', ... } }
// Fix: compound index that includes the sort field
db.orders.createIndex({ userId: 1, createdAt: -1 });
// Now the SORT stage disappears from the planПринудительный выбор индекса с помощью hint()
Планировщик запросов MongoDB обычно выбирает лучший индекс, но иногда отдаёт предпочтение неоптимальному плану, особенно если статистика устарела. С помощью .hint() можно принудительно выбрать определённый индекс, передав шаблон ключей индекса или его имя. Это полезно для отладки и сравнения планов, а также в качестве крайней меры в рабочей среде, когда планировщик принимает неудачные решения.
// Force use of a specific index by key pattern
db.orders.find({ userId: 'u1', status: 'active' })
.hint({ userId: 1, status: 1 })
.explain('executionStats');
// Force by index name
db.orders.find({ userId: 'u1' })
.hint('idx_orders_user');
// Force a COLLSCAN (bypass all indexes)
db.orders.find({ userId: 'u1' })
.hint({ $natural: 1 });explain() для конвейеров агрегации
Конвейеры агрегации также поддерживают explain(). Передайте { explain: true } в aggregate(), чтобы увидеть выполнение этапов конвейера и проверить, используют ли ранние этапы, например $match, индексы. Главное: $match в начале конвейера может передать фильтр на уровень IXSCAN, а $match после $group этого сделать не может.
// explain() on an aggregation pipeline
db.orders.explain('executionStats').aggregate([
{ $match: { userId: 'u1', status: 'active' } }, // <-- pushed to IXSCAN
{ $group: { _id: '$productId', total: { $sum: '$amount' } } },
{ $sort: { total: -1 } }
]);Распространённые тревожные признаки в explain()
При анализе результата explain() обращайте внимание на следующие предупреждающие признаки: COLLSCAN для большой коллекции; значение totalDocsExamined, намного превышающее nReturned; находящийся в памяти этап SORT; или executionTimeMillis, превышающий Ваш SLA. Каждый из них указывает на конкретное исправление: добавить индекс, изменить порядок ключей индекса, добавить поля сортировки в составной индекс или переработать запрос.
// Red flag checklist:
// 1. stage: 'COLLSCAN' -> add index
// 2. totalDocsExamined >> nReturned -> compound index or partial index
// 3. stage: 'SORT' -> extend compound index to cover sort order
// 4. executionTimeMillis > 100 -> investigate stages aboveБыстрая проверка
Проверьте, насколько хорошо Вы усвоили работу с результатом explain() в MongoDB из этого урока.
Итоги урока
В этом уроке Вы узнали, что explain('executionStats') выполняет запрос и предоставляет данные о времени выполнения и количестве документов, различие между COLLSCAN и IXSCAN в выигрышном плане сразу показывает, использовался ли индекс, а соотношение nReturned / totalDocsExamined измеряет эффективность индекса. Далее Вы изучите текстовые индексы для полнотекстового поиска.
Изучай JavaScript с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 30
- Уроки
- 120
Часто задаваемые вопросы
Урок «Чтение вывода explain() для диагностики запросов» бесплатный?
Да — полный текст урока «Чтение вывода explain() для диагностики запросов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс MongoDB Academy, подпишись на CoddyKit PRO. Курс MongoDB Academy содержит 4 уроков всего.
Чему я научусь в уроке «Чтение вывода explain() для диагностики запросов»?
Вы научитесь интерпретировать этапы IXSCAN и COLLSCAN в выводе explain и выявлять отсутствующие индексы по соотношениям nReturned и docsExamined. Ты практикуешь MongoDB Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать MongoDB Academy?
Предыдущий опыт не требуется. MongoDB Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Чтение вывода explain() для диагностики запросов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке MongoDB Academy?
Да. Каждый урок MongoDB Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Как работают B-деревья индексов MongoDB
- Создание одно-полевых и составных индексов
- Свойства индексов: уникальность, разреженность, частичность, TTL
- Чтение вывода explain() для диагностики запросов