7. Индексы и инструменты

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

Индексы

Индексы помогают фильтрации и сортировке, но занимают место и добавляют работу при записи. Список индексов коллекции показывает db.unicorns.getIndexes(), создание выполняется через createIndex:

db.unicorns.createIndex({name: 1});

И уничтожаются с помощью dropIndex:

db.unicorns.dropIndex({name: 1});

Уникальный индекс может быть создан, если во втором параметре установить unique в true:

db.unicorns.createIndex({name: 1}, {unique: true});

Можно создавать индексы над вложенными полями (опять же, используя точечную нотацию), либо над массивами. Также можно создавать составные индексы:

db.unicorns.createIndex({name: 1, vampires: -1});

Порядок вашего индекса (1 для восходящего и -1 для нисходящего) не играет роли в случае с простым индексом, однако он может быть существенен при сортировке или лимитировании с применением составных индексов.

На странице описания индексов можно найти дополнительную информацию.

Explain

Чтобы увидеть, используются ли индексы в ваших запросах, вызывайте у курсора метод explain:

db.unicorns.find().explain()

Для более подробного отчёта выполните db.unicorns.find().explain("executionStats"). Смотрите выбранные стадии плана, totalDocsExamined, totalKeysExamined и nReturned. Конкретная структура плана зависит от версии; названия старых BasicCursor и BtreeCursor больше не являются универсальными признаками.

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

db.unicorns.find({name: 'Pilot'}).explain()

Запись без подтверждения

Подтверждение записи задаёт write concern. Нельзя считать, что все записи MongoDB по умолчанию не подтверждаются. При w: 0 приложение не получает обычное подтверждение применения записи; проверка ошибки после факта через старый getLastError не заменяет корректный API.

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

Шардинг

MongoDB поддерживает авто-шардинг. Шардинг — это подход к масштабируемости, когда отдельные части данных хранятся на разных серверах. Примитивный пример — хранить данные пользователей, чьё имя начинается на буквы A-M на одном сервере, а остальных — на другом. Возможности шардинга MongoDB значительно превосходят данный простой пример. Рассмотрение шардинга выходит за пределы данной книги, однако вы должны знать, что он существует, и вы должны воспользоваться им, когда ваши задачи выйдут за рамки одного сервера.

Репликация

Replica set содержит primary и secondary. Записи направляются в primary; чтение с secondary зависит от выбранного read preference и может вернуть отстающие данные. При отказе primary новый выбирается по правилам replica set, а не просто назначается произвольный второй сервер.

Главная задача репликации — доступность и отказоустойчивость. Она не заменяет резервные копии и не гарантирует ускорение любого чтения. Проектируйте число голосующих узлов и размещение по документации replica set; старое утверждение об одном общем арбитре для нескольких шардов удалено как некорректный эксплуатационный совет.

Статистика

Статистику базы данных можно получить с помощью вызова db.stats(). В основном информация касается размера вашей базы данных. Также можно получить статистику коллекции, например unicorns, с помощью вызова db.unicorns.stats(). Большая часть получаемой информации, опять же, касается размеров коллекции.

Веб-интерфейс

Устаревший встроенный HTTP-интерфейс и параметр rest=true не являются актуальным способом администрирования. Не открывайте порт 28017 и не включайте старые HTTP/REST-настройки ради этого примера. Для работы используйте mongosh, а для диагностики — штатные команды и инструменты своей версии.

Профайлер

Профилирование добавляет нагрузку и может записывать содержимое запросов. Сначала проверьте текущий уровень через db.getProfilingStatus(). Следующий эксперимент выполняйте только в учебной базе, затем верните прежние настройки. Не включайте уровень 2 на рабочей системе по инструкции из статьи. Профайлер MongoDB можно включить с помощью следующего вызова:

db.setProfilingLevel(2);

Со включённым профайлером можно запустить команду:

db.unicorns.find({weight: {$gt: 600}});

И обратиться к профайлеру:

db.system.profile.find()

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

Можно выключить профайлер, повторно вызвав setProfilingLevel, только передав 0 в качестве аргумента. Можно также передать 1 для профилирования запросов, выполняющихся дольше 100 миллисекунд. Также, можно вторым параметром передать время в миллисекундах:

//профилировать всё, что занимает более 1 секунды
db.setProfilingLevel(1, 1000);

Резервное копирование и восстановление

MongoDB Database Tools устанавливаются и версионируются отдельно от сервера. mongodump и mongorestore создают и восстанавливают BSON-дампы. Для рабочей базы отдельно проверяйте совместимость версий, права доступа и согласованность снимка при параллельных изменениях. Ниже показан учебный дамп одной базы:

Например, чтобы сделать резервную копию базы данных learn в папку backup, мы должны выполнить (разумеется не в консоли самой MongoDB, а просто в консоли операционной системы):

mongodump --uri="mongodb://127.0.0.1:27017" --db learn --out backup

Проверьте восстановление в отдельной базе learn_restore, чтобы не менять исходные учебные данные:

mongorestore --db learn_restore --collection unicorns backup/learn/unicorns.bson

Также, стоит упомянуть, что есть две утилиты mongoexport и mongoimport, предназначенные для экспорта и импорта данных в виде JSON и CSV. Например, можно получить результат в виде JSON следующим образом:

mongoexport --db learn --collection unicorns

И CSV:

mongoexport --db learn --collection unicorns --type=csv --fields=name,weight,vampires

mongoexport и mongoimport предназначены для обмена данными, а не полноценной резервной копии: вместе с документами важны типы, индексы и метаданные. Даже успешный mongodump ещё не доказывает пригодность копии — выполните тестовое восстановление и проверку содержимого. Метод резервирования рабочей системы выбирайте по топологии и требованиям к согласованности.

В этой главе

Перед оптимизацией измерьте запрос, проверьте план, размер коллекции и нагрузку. Индексирование, подтверждение записи, репликация, профилирование и резервирование решают разные задачи. Не меняйте настройки устойчивости ради неподтверждённого обещания скорости.

Дальше в книгеЗаключение →
Karl Seguin · перевод @jsmarkus · CC BY-NC 3.0 и авторы