Итог / tl;dr: Индекс 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 }});
Ваш пробег будет варьироваться.
person
mnemosyn
schedule
19.06.2012