2012-06-15 6 views
3

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

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

Как Монго можно использовать ABC индекс в запросе для переменного тока и насколько эффективным является индекс в этом случае?

фона:

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

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

ответ

2

нижняя линия/лин; др: Index b может быть «пропущен», если a и c опрашиваются для равенства или неравенства, а не, например, для сортов на c.

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

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

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

Понятно, что можно использовать индекс A, который, в зависимости от селективности A, безусловно, очень полезен. «Пропуск» B может быть сложным, или нет. Давайте держать это похоже на Kyle's cookbook example:

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

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

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

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

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

По существу, существует только два класса запросов: те, где 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 }}); 

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

+0

Спасибо, это, пожалуй, лучшая информация, которую мы можем получить, учитывая (отмеченную) отсутствие авторитетных ссылок. В моем конкретном случае B - столбец с низкой избирательностью, и я делаю запрос «начинается с» на C. Итак, полагаю, исходя из вашего ответа, мой индекс ABC почти так же хорош как индекс AC для запроса в AC? Я знаю, что пробег будет меняться, поэтому я могу просто пойти с индексами AC и ABC на время ... –

+0

Я думаю, он будет почти таким же хорошим, как AC-index, если вы не сортируете на C, а ' Объяснение() 'может вам точно сказать. Следите за «nscanned», он не должен быть намного больше, чем 'n'. – mnemosyn

1

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

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

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

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

+0

Другими словами, вы говорите, что когда вы запрашиваете AC, индекс ABC не лучше индекса на A в одиночку? –

+0

Это лучше, потому что он может отфильтровывать нежелательные значения в C из самого индекса, без необходимости читать документ. – Eduardo

+0

-1 @Eduardo Я не думаю, что следую многим вашим рассуждениям здесь. Как он может использовать C-часть индекса? Довольно сложно задуматься о цели индекса, чтобы не «загрузить весь документ». Фактически, вы должны думать об этом с точки зрения количества документов, которые необходимо отсканировать (nscan). –