В первой части этой серии мы познакомились с индексацией в MongoDB. мы увидели, как создавать, использовать и анализировать запросы с индексами, что дает нам хорошую основу для дальнейшего развития. В этой части мы рассмотрим еще несколько небольших, но важных концепций, таких как индексация вложенных документов и встроенных полей, покрытые запросы и направление индекса.
Конечно, эта часть предполагает, что вы знаете, как создать индекс для a и использовать метод explain()
для его анализа. Если вы еще не знаете, как, я предлагаю вам вернуться и прочитать первую часть, прежде чем продолжить здесь.
Мы использовали коллекцию именованных posts
в прошлой статье. Для нашей работы здесь, давайте добавим новое location
поля к нему, чтобы сохранить местоположение, из которого была сделана запись. Поле является вложенным документом и хранит город, штат и страну пользователя, как показано ниже (вложенный документ — это поле, имеющее структуру документа):
{ "_id": ObjectId("5146bb52d852470060001f4"), "comments": { "0": "This is the first comment", "1": "This is the second comment" }, "post_likes": 40, "post_tags": { "0": "MongoDB", "1": "Tutorial", "2": "Indexing" }, "post_text": "Hello Readers!! This is my post text", "post_type": "private", "user_name": "Mark Anthony", "location": { "city": "Los Angeles", "state": "California", "country": "USA" } }
Индексация на поддокументы
Предположим, мы хотим искать сообщения в зависимости от того, где живет пользователь. Для этого нам нужно создать индекс в поле location
поддокумента, который, в свою очередь, индексирует подполя. Тогда мы сможем использовать индекс для следующих типов запросов:
<?php // query to find posts from the city of Los Angeles $cursor = $collection->find( array( "location" => "Los Angeles" ), array() ); // query to find posts from the state of California $cursor = $collection->find( array( "location" => "California" ), array() ); // query to find posts from the United States $cursor = $collection->find( array( "location" => "USA" ), array() );
Мы можем выполнить поиск во всех подполях ( city
, state
и country
) в поддокументе, используя только location
в качестве ключа. Запрос проверяет, соответствуют ли какие-либо из подполей location
нашим критериям поиска.
Следует отметить, что, как и при индексировании массивов, для всех подполей создаются внутренние индексы. В этом случае три индекса создаются как location.city
, location.state
и location.country
, поэтому такие индексы следует использовать с осторожностью, поскольку каждый индекс занимает место в памяти.
Индексирование по встроенным полям
Иногда бывает, что нам не нужны индексы для всех полей вложенного документа. Если в нашем приложении мы хотим найти сообщения только по городу, но не по штату или стране, мы можем создать индекс для встроенного поля city
.
Теперь мы можем использовать этот индекс в запросах для поиска постов по городу:
<?php // query to find posts from the city of Los Angeles $cursor = $collection->find( array( "location.city" => "Los Angeles" ), array() );
Направление индекса (по возрастанию / по убыванию)
Мы всегда указываем направление индекса (1 или -1) для ключей при создании наших индексов. Я кратко коснулся этого в первой части, но на самом деле это важный вопрос для обсуждения, который я хотел бы снова затронуть. Если у нас есть один ключ в индексе, направление 1 или -1 на самом деле не имеет значения, но оно вступает в игру, когда мы выполняем сортировку или ранжирование запросов с составными индексами.
Предположим, у нас есть составной индекс с ключом field1
возрастанию и ключом field2
убыванию. В этом случае таблица индексации может выглядеть так:
Запрос с сортировкой по возрастанию field1
восходящему field2
будет перемещать строки в следующем порядке: 1, 2, 3, 4, 5, 6, 7, 8, 9. Запрос с возрастанием field2
убыванию field2
будет перемещаться: 3, 2, 1, 6, 5, 4, 9, 8, 7. Такие скачки не по порядку в дереве поиска могут оказаться дорогостоящими для производительности запросов.
Конечно, структура индекса выше представлена в виде таблицы только для понимания. Помните, MongoDB использует древовидные структуры внутри себя; каждый элемент хранится как узел дерева. Элементы, расположенные ближе друг к другу, будут находиться под одинаковыми ветвями и, следовательно, легко доступны. Если запрос должен извлечь несколько записей в отсортированном виде, было бы логично правильно разместить элементы рядом друг с другом в дереве для более быстрого поиска по сравнению со случаем, когда запрос должен перейти с одного узла на другой дальний узел, чтобы захватить элементы.
Если вы хотите выполнить сортировку по field1:1,field2:1
, то индекс {field1:1, field2:1}
будет быстрее, чем {field1:1, field2:-1}
или {field1:-1, field2:1}
Покрытые Запросы
Согласно документации MongoDB, покрытый запрос — это тот, в котором:
- все поля, используемые в запросе, являются частью индекса, используемого в запросе, и
- все поля, возвращенные в результатах, имеют одинаковый индекс
Поскольку все поля охватываются самим индексом, MongoDB может соответствовать условию запроса, а также возвращать поля результатов, используя тот же индекс, не заглядывая в документы. Поскольку индексы хранятся в ОЗУ или последовательно расположены на диске, такой доступ намного быстрее.
post_type
у нас есть составной индекс, определенный в post_type
и post_type
. Этот индекс охватывает следующий запрос:
<?php // query to find posts with type public and get only user_name in result $cursor = $collection->find( array( "post_type" => "public", ), array( "user_name" => 1, "_id" => 0 ) );
Мы явно исключили поле _id
из результата, чтобы воспользоваться покрытым запросом. Как вы уже знаете, все запросы возвращают поле _id
по умолчанию. Согласно второму условию для покрытых запросов, все поля, возвращаемые в результате, должны быть включены в индекс. У нас нет _id
в нашем составном индексе для post_type
и post_type
, поэтому мы должны исключить это поле из результата.
Чтобы проверить, покрыт ли запрос, мы можем посмотреть в поле indexOnly
в результате метода explain()
. Истинное значение указывает, что наш запрос был закрытым.
Важно знать, что индекс не может покрыть запрос, если:
- любое из проиндексированных полей является массивом (например,
post_tags
), или - любое из проиндексированных полей является полями в поддокументах (например,
location.city
)
Таким образом, всегда полезно проверять использование индекса запроса с помощью explain()
.
Удаление индексов
Чтобы проверить текущий размер индекса для базы данных, мы можем использовать метод totalIndexSize()
который возвращает размер индекса в байтах.
Нам просто нужно убедиться, что у нас достаточно оперативной памяти для размещения индексов, а также данных, которыми MongoDB управляет и которые регулярно использует.
Чтобы удалить существующий индекс и, таким образом, освободить ресурсы, мы используем метод dropIndex()
.
Вывод
Это все для этой части, а также серии. Мы затронули много важных тем, чтобы вы смогли быстрее освоить индексирование в MongoDB.
Анализ ваших индексов, чтобы убедиться, что они работают хорошо, — это непрерывный процесс по мере роста вашего приложения и изменения ваших данных, поэтому, если у вас есть какие-либо добрые вопросы или комментарии по поводу этой статьи, не стесняйтесь размещать их в комментариях ниже.
Изображение через Fotolia