Статьи

MongoDB Indexing, часть 2

В первой части этой серии мы познакомились с индексацией в 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 .

Монго-2-1

Теперь мы можем использовать этот индекс в запросах для поиска постов по городу:

 <?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 убыванию. В этом случае таблица индексации может выглядеть так:

Монго-2-2

Запрос с сортировкой по возрастанию 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() . Истинное значение указывает, что наш запрос был закрытым.

Монго-2-3

Важно знать, что индекс не может покрыть запрос, если:

  • любое из проиндексированных полей является массивом (например, post_tags ), или
  • любое из проиндексированных полей является полями в поддокументах (например, location.city )

Таким образом, всегда полезно проверять использование индекса запроса с помощью explain() .

Удаление индексов

Чтобы проверить текущий размер индекса для базы данных, мы можем использовать метод totalIndexSize() который возвращает размер индекса в байтах.

Монго-2-4

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

Чтобы удалить существующий индекс и, таким образом, освободить ресурсы, мы используем метод dropIndex() .

mongo2-5

Вывод

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

Анализ ваших индексов, чтобы убедиться, что они работают хорошо, — это непрерывный процесс по мере роста вашего приложения и изменения ваших данных, поэтому, если у вас есть какие-либо добрые вопросы или комментарии по поводу этой статьи, не стесняйтесь размещать их в комментариях ниже.

Изображение через Fotolia