Как работают B-деревья индексов MongoDB
Вы проследите, как MongoDB хранит записи индекса в B-дереве и как планировщик запросов обходит дерево для выполнения фильтра.
«Как работают B-деревья индексов MongoDB» — бесплатный урок MongoDB Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения MongoDB Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс MongoDB Academy содержит 4 уроков всего.
Зачем нужны индексы
Без индекса MongoDB должна просматривать каждый документ в коллекции, чтобы выполнить запрос. Это называется сканированием коллекции (COLLSCAN). В коллекции с миллионами документов COLLSCAN может занимать секунды и даже минуты. Индекс — это отдельная упорядоченная структура данных, которая позволяет MongoDB напрямую переходить к подходящим документам за микросекунды.
Структура данных B-дерева
MongoDB использует B-дерево (сбалансированное дерево) для хранения записей индекса. B-дерево организовано в виде иерархии узлов: корневой узел находится наверху, внутренние узлы — в середине, а листовые узлы — внизу. Каждый узел содержит несколько пар «ключ—значение» и указатели на дочерние узлы. Дерево остаётся сбалансированным — все листовые узлы находятся на одной глубине, поэтому поиск всегда занимает одинаковое количество шагов независимо от того, какое значение Вы ищете.
Как хранятся записи индекса
Когда Вы создаёте индекс по полю, например age, MongoDB строит B-дерево, где каждая запись в листовом узле содержит значение индексируемого поля и указатель (RecordId) на фактический документ на диске. Записи сортируются по возрастанию или убыванию в зависимости от того, как Вы определили индекс. Поскольку дерево отсортировано, MongoDB может выполнять поиск по равенству, запросы по диапазону и операции сортировки, используя одну и ту же структуру.
// Index on 'age' field
db.users.createIndex({ age: 1 });
// MongoDB now has a sorted B-tree:
// 18 -> RecordId(doc1)
// 25 -> RecordId(doc4)
// 31 -> RecordId(doc2)
// 47 -> RecordId(doc7)Планировщик запросов и IXSCAN
Каждый запрос проходит через планировщик запросов MongoDB, который оценивает доступные индексы и выбирает наиболее эффективный план выполнения. Когда планировщик находит подходящий индекс, он использует этап IXSCAN (сканирование индекса) вместо COLLSCAN. IXSCAN проходит по B-дереву от корневого узла к листовым узлам, соответствующим условию, а затем извлекает с диска только нужные документы, используя указатели RecordId.
// See which plan MongoDB chose
db.users.find({ age: { $gt: 30 } }).explain('executionStats');Использование индексов для равенства, диапазонов и сортировки
Индекс B-дерева поддерживает три типа доступа: поиск по равенству (поиск точного ключа), сканирование диапазона (проход по последовательным листовым узлам между двумя границами) и операции сортировки (дерево уже упорядочено, поэтому сортировка в памяти не требуется). Благодаря этим трём возможностям удачно размещённый индекс оказывается значительно полезнее, чем может показаться сначала.
// Equality - single leaf node lookup
db.users.find({ username: 'alice' });
// Range - scan contiguous leaf nodes
db.users.find({ age: { $gte: 20, $lte: 30 } });
// Sort - traverses tree in order, no sort stage
db.users.find({}).sort({ age: 1 });Направление индекса: по возрастанию и по убыванию
При создании индекса с 1 записи хранятся в порядке возрастания, а -1 задаёт порядок убывания. Для индекса по одному полю направление не имеет большого значения, поскольку MongoDB может проходить по B-дереву в обоих направлениях. Направление становится критически важным для составных индексов, где сочетание направлений должно соответствовать порядку сортировки, используемому запросами.
// Ascending index
db.orders.createIndex({ createdAt: 1 });
// Descending index (useful for 'newest first' sorts)
db.orders.createIndex({ createdAt: -1 });Размер индекса и память
MongoDB старается держать рабочий набор индексов в RAM (в кэше WiredTiger). Если индекс полностью помещается в памяти, операции ввода-вывода при поиске практически не требуют затрат. Если индекс слишком велик для RAM, MongoDB вынуждена подгружать узлы индекса с диска, что вызывает резкие скачки задержки. Поэтому индексы следует делать компактными: индексируйте только поля, по которым Вы действительно выполняете запросы, и используйте проекцию, чтобы не возвращать ненужные данные.
// Check index sizes in bytes
db.users.stats().indexSizes;
// Example output:
// { '_id_': 856064, 'age_1': 442368 }Запросы, покрываемые индексом
Запрос, покрываемый индексом, — это запрос, в котором все поля фильтра и проекции присутствуют в индексе. MongoDB может обработать такой запрос, используя только B-дерево индекса, и ей не потребуется извлекать фактический документ с диска. Такие запросы выполняются чрезвычайно быстро, поэтому их стоит предусматривать для наиболее часто используемых операций чтения.
// Index on email and name
db.users.createIndex({ email: 1, name: 1 });
// Covered query: filter on email, project email+name only
// MongoDB only reads the index, never the document
db.users.find(
{ email: 'a@b.com' },
{ _id: 0, email: 1, name: 1 }
);Индекс _id присутствует всегда
Каждая коллекция MongoDB автоматически получает уникальный индекс B-дерева по полю _id. Именно благодаря этому индексу поиск по _id всегда выполняется быстро, даже в огромных коллекциях. Удалить индекс _id нельзя. Все остальные индексы необязательны, и разработчик или DBA должны создавать их явно.
// MongoDB creates this automatically:
// { '_id': 1 } (unique)
// Fast because _id is always indexed:
db.orders.findOne({ _id: ObjectId('64a1f...') });Накладные расходы индексов при записи
Индексы ускоряют чтение, но замедляют запись. При каждой вставке, модификации или удалении необходимо обновлять не только документ на диске, но и каждое B-дерево, индексирующее поле этого документа. Коллекция с 10 индексами требует 10 дополнительных операций записи в B-деревья при каждой вставке. Поэтому следует создавать только индексы, обслуживающие реальные шаблоны запросов: неиспользуемые индексы всё равно увеличивают стоимость записи.
// List all indexes and their sizes
db.users.getIndexes();
// Identify unused indexes (MongoDB 4.4+)
// $indexStats shows usage counts since last restart
db.users.aggregate([{ $indexStats: {} }]);Индексы с несколькими ключами для массивов
Когда Вы индексируете поле, содержащее массив, MongoDB создаёт индекс с несколькими ключами и добавляет по одной записи в B-дерево для каждого элемента массива. Благодаря этому такие запросы, как { tags: 'mongodb' }, могут использовать индекс, даже если tags является массивом. MongoDB автоматически обнаруживает поля-массивы и устанавливает признак индекса с несколькими ключами; при создании индекса не требуется предпринимать никаких дополнительных действий.
// Document with array field
// { title: 'Guide', tags: ['mongodb', 'nosql', 'database'] }
// Single index creation
db.articles.createIndex({ tags: 1 });
// MongoDB creates THREE B-tree entries:
// 'database' -> RecordId
// 'mongodb' -> RecordId
// 'nosql' -> RecordId
// This query now uses IXSCAN
db.articles.find({ tags: 'mongodb' });Быстрая проверка
Проверьте, насколько хорошо Вы поняли материал этого урока об индексах B-дерева в MongoDB.
Итоги урока
В этом уроке Вы узнали, что MongoDB использует структуры B-деревьев, в которых отсортированные записи в листовых узлах указывают на RecordIds документов; планировщик запросов выбирает IXSCAN вместо COLLSCAN, если существует подходящий индекс; а индексы ускоряют чтение, но увеличивают накладные расходы при записи. Далее мы рассмотрим создание индексов по одному полю и составных индексов.
Изучай JavaScript с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 30
- Уроки
- 120
Часто задаваемые вопросы
Урок «Как работают B-деревья индексов MongoDB» бесплатный?
Да — полный текст урока «Как работают B-деревья индексов MongoDB» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс MongoDB Academy, подпишись на CoddyKit PRO. Курс MongoDB Academy содержит 4 уроков всего.
Чему я научусь в уроке «Как работают B-деревья индексов MongoDB»?
Вы проследите, как MongoDB хранит записи индекса в B-дереве и как планировщик запросов обходит дерево для выполнения фильтра. Ты практикуешь MongoDB Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать MongoDB Academy?
Предыдущий опыт не требуется. MongoDB Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Как работают B-деревья индексов MongoDB»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке MongoDB Academy?
Да. Каждый урок MongoDB Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Как работают B-деревья индексов MongoDB
- Создание одно-полевых и составных индексов
- Свойства индексов: уникальность, разреженность, частичность, TTL
- Чтение вывода explain() для диагностики запросов