У меня есть составной _id, содержащий 3 числовых свойства:

_id ": {" KeyA ": 0," KeyB ": 0," KeyC ": 0}

Рассматриваемая база данных имеет 2 миллиона идентичных значений для KeyA и кластеры по 500 000 идентичных значений для KeyB.

Насколько я понимаю, я могу эффективно запрашивать KeyA и KeyB с помощью команды:

find( { "_id.KeyA" : 1, "_id.KeyB": 3 } ).limit(100)

Когда я объясняю этот запрос, результат:

"cursor" : "BasicCursor",
"nscanned" : 1000100,
"nscannedObjects" : 1000100,
"n" : 100,
"millis" : 1592,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {}

Без limit () результат будет:

"cursor" : "BasicCursor",
"nscanned" : 2000000,
"nscannedObjects" : 2000000,
"n" : 500000,
"millis" : 3181,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {}

Насколько я понимаю, BasicCursor означает, что индекс был проигнорирован, и оба запроса имеют большое время выполнения - даже когда я запросил только 100 записей, это занимает ~ 1,5 секунды. Я намеревался использовать ограничение для реализации разбивки на страницы, но это явно слишком медленно.

Команда:

find( { "_id.KeyA" : 1, "_id.KeyB": 3, , "_id.KeyC": 1000 } )

Правильно использует BtreeCursor и быстро выполняет, предлагая правильное составное _id.

Я использую MongoDb версии 1.8.3. Может ли кто-нибудь уточнить, вижу ли я ожидаемое поведение или неправильно понял, как использовать / запрашивать составной индекс?

Спасибо, Пол.

4
Paul 30 Авг 2011 в 20:21

2 ответа

Лучший ответ

Индекс не является составным индексом, а является индексом всего значения поля _id. MongoDB не смотрит в индексированное поле, а вместо этого использует необработанное представление поля BSON для сравнения (если я правильно прочитал документы).

Чтобы делать то, что вы хотите, вам нужен фактический составной индекс по {_id.KeyA: 1, _id.KeyB: 1, _id.KeyC: 1} (который также должен быть уникальным индексом). Поскольку у вас не может быть индекса для _id, вам, вероятно, будет лучше оставить его как ObjectId (что приведет к уменьшению индекса и потере места) и сохраните свой KeyA, Поля KeyB и KeyC как свойства вашего документа. Например. {_id: ObjectId("xyz..."), KeyA: 1, KeyB: 2, KeyB: 3}

11
Theo 30 Авг 2011 в 17:03

Вам понадобится отдельный составной индекс для желаемого поведения. В общем, я не рекомендую использовать объекты в качестве _id, потому что порядок ключей важен при сравнении, поэтому {a: 1, b: 1} не равно {b: 1, a: 1}. Поскольку не все водители сохраняют ключевой порядок в объектах, очень легко выстрелить себе в ногу, сделав что-то вроде этого:

db.foo.save(db.foo.findOne())
8
mstearn 30 Авг 2011 в 16:39