Монго тройной составной индекс

Если у вас есть двойной составной индекс { a: 1, b: 1}, для меня имеет смысл, что индекс не будет использоваться, если вы выполняете запрос только по одному b (т.е. вы не можете "пропустить" a в своем запросе). Индекс, однако, будет использоваться, если вы запрашиваете только один.

Однако, учитывая тройной составной индекс { a: 1, b: 1, c: 1}, моя команда объяснения показывает, что индекс используется, когда вы запрашиваете a и c (т.е. вы можете "пропустить" b в своем запросе).

Как Mongo может использовать индекс abc в запросе для ac, и насколько эффективен индекс в этом случае?

Фон:

Мой вариант использования заключается в том, что иногда я хочу сделать запрос к a, b, c, а иногда я хочу сделать запрос к a, c. Теперь я должен создать только 1 индекс для a, b, c или я должен создать один для a, c и один для a, b, c?

(Не имеет смысла создавать индекс для a, c, b, потому что c является многоключевым индексом с хорошей избирательностью.)

2 ответа

Решение

нижняя строка / tl; dr: Index b можно пропустить, если a а также c запрашиваются на равенство или неравенство, но не, например, для сортировки на c,

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

Все это довольно сложно, потому что это зависит от селективности ваших индексов и от того, запрашиваете ли вы равенство, неравенство и / или сортировку, поэтому explain() твой единственный друг, но вот что я нашел:

Предостережение: то, что приходит сейчас, это смесь экспериментальных результатов, рассуждений и догадок. Возможно, я слишком далеко перехожу к аналогии с Кайлом, и могу даже ошибаться (и не повезло, потому что результаты моих тестов слабо совпадают с моими рассуждениями).

Понятно, что можно использовать индекс А, что, в зависимости от селективности А, безусловно, очень полезно. "Пропуск" B может быть сложным или нет. Давайте сохраним это как пример поваренной книги Кайла:

French
    Beef
        ...
    Chicken
        Coq au Vin
        Roasted Chicken
    Lamb
        ...
    ...

Если вы сейчас попросите меня найти какое-нибудь французское блюдо под названием "Шатобриан", я могу использовать индекс A и, поскольку я не знаю ингредиента, придется сканировать все блюда в A, С другой стороны, я знаю, что список блюд в каждой категории отсортирован по индексу C поэтому мне нужно будет искать только строки, скажем, "Ча" в каждом списке ингредиентов. Если будет 50 ингредиентов, мне понадобится 50 поисков вместо одного, но это намного лучше, чем сканировать каждое французское блюдо!

В моих экспериментах число было намного меньше, чем число различных значений в b: оно никогда не превышало 2. Однако я проверил это только с одной коллекцией, и это, вероятно, связано с селективностью b -индекс.

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

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

По сути, есть только два класса запросов: те, где nscanned <= 2 * limit и те, которые должны сканировать всю коллекцию (120 тыс. документов). Индекс {a, b, c}:

// fast (range query on c while skipping b)
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }});
// slow (sorting)
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "c" : -1});
> db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "b" : -1}); 

// fast (can sort on c if b included in the query)
> db.Test.find({"a" : 43, "b" : 7887, "c" : { $lte : 45454 }}).sort({ "c" : -1});

// fast (older tutorials claim this is slow)
> db.Test.find({"a" : {$gte : 43}, "c" : { $lte : 45454 }});

Ваш пробег будет меняться.

Вы можете рассматривать запросы к A и C как особый случай запросов к A (в этом случае будет использоваться индекс). Использование индекса более эффективно, чем загрузка всего документа.

Предположим, что вы хотите получить все документы с A от 7 до 13 и C от 5 до 8.

Если бы у вас был индекс только для A: база данных могла бы использовать индекс для выбора документов с A между 7 и 13, но, чтобы убедиться, что C был между 5 и 8, ей также пришлось бы получать соответствующие документы.

Если у вас был индекс для A, B и C: база данных могла бы использовать индекс для выбора документов с A между 7 и 13. Поскольку значения C уже сохранены в записях индекса, она могла бы определить, соответствует ли документы также соответствуют критерию С, без необходимости извлечения этих документов. Таким образом, вы избежите чтения с диска, с лучшей производительностью.

Другие вопросы по тегам