Раздел 36 · MongoDB с нуля

Индексы: зачем и какие бывают

junior~15 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

В прошлом уроке мы соединяли коллекции и считали новые поля. Все наши запросы до сих пор работали на девяти книгах, и любой отвечал мгновенно. В настоящем магазине книг десятки тысяч, а заказов миллионы. Тогда важно не только что спросить, но и как база будет искать ответ. Сегодня знакомимся с главным инструментом скорости: индексом.

Предметный указатель

Нужно найти в толстом учебнике всё про рекурсию. Можно листать с первой страницы до последней и читать каждую. А можно открыть предметный указатель в конце книги: слова там стоят по алфавиту, рядом номера страниц. Находишь «рекурсия», видишь «стр. 45, 112, 304» и открываешь только их.

Индекс в MongoDB это такой указатель для коллекции. Значения выбранного поля лежат в нём по порядку, рядом ссылки на документы. Чтобы найти книги жанра «роман», серверу не нужно перебирать все документы: он находит «роман» в упорядоченном списке и сразу идёт к нужным книгам.

Без индекса сервер делает то же, что читатель без указателя: перебирает всю коллекцию. Такой перебор называется полным просмотром коллекции. Как его увидеть в цифрах, разберём в следующем уроке.

Если ты прошёл вводный урок про индексы в PostgreSQL, идея та же самая. В обеих базах обычный индекс устроен как B-дерево.

Индекс, который есть всегда

Посмотрим, какие индексы уже есть у книг:

db.books.getIndexes()
[ { v: 2, key: { _id: 1 }, name: '_id_' } ]

Один индекс уже есть, хотя мы его не создавали. MongoDB строит индекс по _id для каждой коллекции сама и не даёт его удалить. Поэтому поиск по _id быстрый всегда, а два документа с одинаковым _id в коллекцию не попадут: этот индекс уникальный.

В ответе три поля: v это версия формата индекса, key говорит, по какому полю и в каком порядке он построен (1 по возрастанию), а name это имя индекса.

Создаём индекс

Магазин часто показывает книги одного жанра. Создадим индекс по genre:

db.books.createIndex({ genre: 1 })
genre_1

createIndex принимает описание: поле и направление. Возвращает он имя, которое MongoDB собрала сама: имя поля и направление через подчёркивание. Если индекс с таким описанием уже есть, повторный вызов ничего не сломает и вернёт то же имя.

Индекс можно построить и по вложенному полю, и по нескольким полям сразу:

db.books.createIndex({ 'author.name': 1, year: -1 })
author.name_1_year_-1

Это составной индекс: книги упорядочены по имени автора, а у одного автора от новых к старым. Он поможет странице «все книги автора, сначала свежие». Как правильно выбирать порядок полей в составном индексе, разберём позже в разделе, в кластере про индексы и производительность.

Теперь индексов три:

[
  { v: 2, key: { _id: 1 }, name: '_id_' },
  { v: 2, key: { genre: 1 }, name: 'genre_1' },
  {
    v: 2,
    key: { 'author.name': 1, year: -1 },
    name: 'author.name_1_year_-1'
  }
]

Имя можно задать и своё, вторым аргументом: db.books.createIndex({ title: 1 }, { name: 'by_title' }) вернёт by_title.

урок из курса

Урок из курса «MongoDB с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.