Про хешированные индексы
Судя по
документации, MongoDB не поддерживает хешированные индексы для массивов.
Хешированные индексы нужны для того, что бы более равномерно распределить данные, которые расположены близко к друг другу. Их часто применяют при шардировании коллекций (когда одна коллекция разбита на несколько частей, которые хранятся на разных серверах). В таком случае, запросы на выбор этих данных не будут идти всегда на один и тот же сервер. Но если у вас запросы вида
поле1 > значение1 && поле1 < значение2
, то индекс использоваться не будет (потому что в таком случае монге надо будет сгенерировать все возможные промежуточные значения и посчитать для них хеши, что невозможно).
Но судя по документации, хешированные индексы также можно применять и для embedded-документов (сам так не делал), но подозреваю, что в таком случае в запросе надо передавать весь embedded-документ, что бы для него правильно посчитался хеш.
Про индексы в целом
В целом, задача индекса в том, что бы после первичного поиска по нему осталось как можно меньше документов для последующего перебора, поэтому рекомендуется строить индекс по полям, которые у вас гарантированно участвуют в каждом запросе.
Скажем, у вас в коллекции проиндексированно только поле
username
и вы выполняете свой запрос вида
$or: [
["username" : "user1", tags: "tag4"],
["username" : "user2", tags: "tag1"],
["username" : "user2", tags: "tag3"],
]
в таком случае, MongoDB с помощью индекса очень быстро выберет все документы, у которых
username
равен либо
user1
, либо
user2
, а затем уже начнёт перебирать найденные документы и проверять их на совпадение остальным параметрам запроса.
Получается, лучше делать составной индекс username + tags
?
Не всегда. При использовании в индексе поля типа
Array
, на каждый элемент массива будет создана
отдельная запись в индексе.
Если у вас мало документов, у которых поле
username
имеет одинаковое значение, но при этом в массиве
tags
может быть много значений, и значения внутри одного массива могут повторяться, то использование составного индекса приведёт к б
ольшему количеству одинаковых записей в индексе, чем если бы вы использовали индексацию только по полю
username
.
Отсюда же вытекает другое ограничение: в составном индексе только одно из полей может быть массивом, иначе в индексе на каждый документ пришлось бы создавать
N ・ M
записей, где N и M - размеры массивов, которые участвуют в построении индекса.
Отдельное поле с хешем
В таком случае, вам при каждом редактировании документа надо будет загружать полный документ из базы, обновлять его, вычислять вручную новый хеш и сохранять документ обратно. А значит вы не сможете использовать запросы, которые обновляют только отдельные поля, например прямое
редактирование массива.
Отдельная коллекция с хешами
Транзакционность в MongoDB есть только на уровне отдельного документа. А это значит, что вам придётся самому следить за консистентностью данных в обеих коллекциях, что может обернуться той ещё головной болью: что вы будете делать, если документ был отредактирован, но информация в связанной коллекции по каким-то причинам не была обновлена (например, прервалась связь с БД или приложение упало из-за нехватки памяти)? Поэтому лично я в общем случае такой подход не рекомендовал бы.
Так что же делать?
Самое простое и эффективное, что вы можете сделать - поднять монгу локально, сгенерировать в ней реалистичные данные, поиграться с разными настройками индексов и замерить скорость выполнения запросов.
Дополнительно можете воспользоваться
методом explain, что бы посмотреть статистику выполнения запроса.