Считывает ли сканирование полной коллекции Mongo каждое отдельное слово в коллекции?

#mongodb

#mongodb

Вопрос:

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

В крайнем случае, предположим, что у каждого объекта есть authorName поле, bookTitles поле и bookFullText поле (где было собрано содержимое всех их романов).

Если бы не было индекса, и вы искали список authorNames , должен ли он считывать все содержимое всех полей во всей коллекции или он будет считывать только authorName поля и имена, но не содержимое других полей?

Комментарии:

1. Документы хранятся на диске в формате BSON (формат двоичной сериализации). Итак, чтобы извлечь одно поле из документа, весь документ BSON должен быть прочитан с диска и десериализован. И даже более того, в зависимости от механизма хранения, документы BSON могут кэшироваться в виде групп, т. Е. Для чтения / записи одного документа MongoDB может фактически считывать / записывать кучу документов и хранить их во внутреннем кэше.

Ответ №1:

Поля в документе упорядочены. Сервер хранит документы в виде списков пар ключ-значение. Поэтому я ожидаю, что, если сервер выполняет сканирование коллекции и сравнение полей, сервер будет:

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

Вышесказанное относится к сравнениям. Как насчет чтения с диска?

Базовая структура базы данных, с которой я знаком, отделяет логические записи (документы в случае MongoDB, строки таблиц в СУБД) от физических страниц. По соображениям производительности база данных обычно не будет считывать документы с диска, но будет считывать страницы. Таким образом, мне кажется маловероятным, что база данных пропустит некоторые поля при сопоставлении документов со страницами. Я ожидаю, что когда потребуется какое-либо поле документа, весь документ будет считан с диска.

Еще одним подтверждением этой гипотезы является ограничение на 16 МБ документов MongoDB. Это довольно низкое значение, и я подозреваю, что оно установлено таким образом, что сервер может полностью считывать документы в память, не беспокоясь о том, что они могут быть очень большими. Например, Postgres отличает VARCHAR от текстовых типов в том, где хранятся данные — данные VARCHAR хранятся в строке таблицы, а ТЕКСТОВЫЕ данные хранятся отдельно, предположительно, чтобы избежать этой точной проблемы с необходимостью считывать их с диска, если требуется какое-либо значение столбца.

Я не инженер сервера MongoDB, поэтому вышесказанное может быть неправильным.

Ответ №2:

  1. Документы BSON хранятся в обычном регистре (сжатие WiredTiger snappy) в блоках по 32 КБ в 64 МБ (размер по умолчанию) в хранилище, в случае, если размер вашего сжатого документа составляет 48 КБ, в память должны быть загружены два блока по 32 КБ каждый, для распаковки и поиска вашего неиндексированного поля, что является дорогостоящей операцией,более того, если вы выполняете поиск по нескольким документам, обычно они не записываются последовательными блоками, что увеличивает требования к IOPS для вашего внутреннего хранилища, поэтому лучше всего провести некоторый первоначальный анализ и проиндексировать поля, которые вы будете искать в основном, и создавать индексы, индексы (B-tree) очень эффективны, поскольку они хранятся вбольшую часть времени в памяти сжимается (сжатие префикса) и очень быстро для поиска по полю.
  2. В mongodb есть текстовые индексы, которых достаточно для некоторых простых текстовых поисков, или вы можете использовать выражения регулярных выражений.
  3. Если вы будете выполнять полнотекстовый поиск большую часть времени, вам лучше использовать поисковую систему, такую как elasticsearch, которая поддерживает обратные индексы перед базой данных, поскольку обратные индексы уже рассчитали ваши полнотекстовые результаты и могут дать вам результаты в разы быстрее, чем аналогичная операция с использованием стандартных индексов B-дерева.
  4. Если вы используете ATLAS (облачный сервис mongodb), в него уже встроен движок lucene (обратный индекс), который может выполнять полнотекстовый поиск для вас.

Я надеюсь, что мой ответ прольет некоторый свет на эту тему … 🙂

Комментарии:

1. Спасибо. Я бы понял это так, что если у меня есть значительное количество полей (или значительный контент в этих полях), которые недоступны для индексации этой таблицы, я должен перенести их в другую таблицу, особенно если к ним редко обращаются, поскольку все, что они делают, это замедляют работу таблицы?

2. в этом случае определенно поможет уменьшение размера документа…

3. @spencersnygg Если вы читаете только одно (или меньше) поле (полей), то вам следует использовать проекцию . Это вернет документы только с указанными полями с сервера — это тоже оптимизация.

4. @spencersnygg: Если вы выполняете поиск по индексу и вам нужны поля не в индексе, а из документа, все блоки размером 7×32 кб будут загружены в память и будут выполнены поиск по полям. Документы хранятся в нескольких больших файлах WiredTiger в формате BSON, операционная система кэширует самые последние блоки из этих файлов в кэш файловой системы, поэтому в лучшем случае блоки уже находятся в кэше файловой системы, если нет, они будут загружены из хранилища (этого следует избегать, насколько это возможно, для повышения производительности)

5. Проекция @spencersnygg позволяет работать с меньшим количеством полей, что позволяет использовать меньшую память, а ваш запрос find возвращает поля, спроецированные в ваше приложение. Проекция также может быть полезна в запросах агрегации, где этап проекции уменьшает объем данных, передаваемых на следующие этапы. Проекция также может использоваться для выполнения запросов к индексам us и может стать закрытыми запросами.