Улучшение полей запросов существует в MongoDB
Я занимаюсь оценкой MongoDB для наших клиентов. В соответствии с требованиями нам нужно связать с некоторыми объектами ent
набор переменных пар имя-значение.
db.ent.insert({'a':5775, 'b':'b1'})
db.ent.insert({'c':'its a c', 'b':'b2'})
db.ent.insert({'a':7557, 'c':'its a c'})
После этого мне нужно интенсивно запрашивать ent
для наличия полей:
db.ent.find({'a':{$exists:true}})
db.ent.find({'c':{$exists:false}})
Per MongoDB docs:
$существует не очень эффективно даже с индексом, и esp. с {$ exists: true}, так как он будет эффективно сканировать все индексированные значения.
Могут ли эксперты предоставить более эффективный способ (даже со сдвигом парадигмы) быстро справляться с изменением пар имя-значение
Ответы
Ответ 1
Вы можете изменить схему таким образом:
{
pairs:[
{k: "a", v: 5775},
{k: "b", v: "b1"},
]
}
Затем вы индексируете свой ключ:
db.people.ensureIndex({"pairs.k" : 1})
После этого вы сможете выполнить поиск в точном соответствии:
db.ent.find({'pairs.k':"a"})
Если вы перейдете с индексом Sparse и текущей схемой, предложенной @WesFreeman, вам нужно будет создать индекс для каждого ключа, который вы хотите выполнить. Это может повлиять на производительность записи или будет неприемлемым, если ваши ключи не являются статическими.
Ответ 2
Просто перепроектируйте свою схему таким образом, чтобы она была индексируемым запросом. Ваш прецедент - это информация, аналогичная первому примеру приложения, приведенному в MongoDB Полное руководство.
Если вам нужно/нужно удобство result.a
, просто сохраните ключи где-нибудь индексируемыми.
вместо существующего:
db.ent.insert({a:5775, b:'b1'})
делать
db.ent.insert({a:5775, b:'b1', index: ['a', 'b']})
Тогда индексный запрос:
db.end.find({index: "a"}).explain()
{
"cursor" : "BtreeCursor index_1",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : true,
"indexOnly" : false,
"indexBounds" : {
"index" : [
[
"a",
"a"
]
]
}
}
или если вы когда-либо будете запрашивать также по значению:
db.ent.insert({
a:5775,
b:'b1',
index: [
{name: 'a', value: 5775},
{name: 'b', value: 'b1'}
]
})
Это также индексный запрос:
db.end.find({"index.name": "a"}).explain()
{
"cursor" : "BtreeCursor index.name_",
"nscanned" : 1,
"nscannedObjects" : 1,
"n" : 1,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : true,
"indexOnly" : false,
"indexBounds" : {
"index.name" : [
[
"a",
"a"
]
]
}
}
Ответ 3
Я думаю, что редкий индекс - это ответ на этот вопрос, хотя для каждого поля вам понадобится индекс. http://www.mongodb.org/display/DOCS/Indexes#Indexes-SparseIndexes
Разреженные индексы должны помочь с $exists: true query.
Даже если ваше поле не очень разреженное (что в основном задано), оно не поможет вам в этом.
Обновить Я думаю, что я ошибаюсь. Похоже, существует открытая проблема (https://jira.mongodb.org/browse/SERVER-4187), тем не менее, что $exists не использует разреженные индексы. Однако вы можете сделать что-то подобное с помощью find и sort, который выглядит так, как будто он использует разреженный индекс:
db.ent.find({}).sort({a:1});
Здесь полная демонстрация разницы, используя ваши примерные значения:
> db.ent.insert({'a':5775, 'b':'b1'})
> db.ent.insert({'c':'its a c', 'b':'b2'})
> db.ent.insert({'a':7557, 'c':'its a c'})
> db.ent.ensureIndex({a:1},{sparse:true});
Обратите внимание, что find({}).sort({a:1})
использует индекс (BtreeCursor):
> db.ent.find({}).sort({a:1}).explain();
{
"cursor" : "BtreeCursor a_1",
"nscanned" : 2,
"nscannedObjects" : 2,
"n" : 2,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"a" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}
И find({a:{$exists:true}})
выполняет полное сканирование:
> db.ent.find({a:{$exists:true}}).explain();
{
"cursor" : "BasicCursor",
"nscanned" : 3,
"nscannedObjects" : 3,
"n" : 2,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
}
}
Похоже, вы также можете использовать .hint({a: 1}), чтобы заставить его использовать индекс.
> db.ent.find().hint({a:1}).explain();
{
"cursor" : "BtreeCursor a_1",
"nscanned" : 2,
"nscannedObjects" : 2,
"n" : 2,
"millis" : 0,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
"a" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
}
}
Ответ 4
Как установить значение не существующего поля на null
? Затем вы можете запросить их с помощью {field: {$ne: null}}
.
db.ent.insert({'a':5775, 'b':'b1', 'c': null})
db.ent.insert({'a': null, 'b':'b2', 'c':'its a c'})
db.ent.insert({'a':7557, 'b': null, 'c':'its a c'})
db.ent.ensureIndex({"a" : 1})
db.ent.ensureIndex({"b" : 1})
db.ent.ensureIndex({"c" : 1})
db.ent.find({'a':{$ne: null}}).explain()
Здесь вывод:
{
"cursor" : "BtreeCursor a_1 multi",
"isMultiKey" : false,
"n" : 4,
"nscannedObjects" : 4,
"nscanned" : 5,
"nscannedObjectsAllPlans" : 4,
"nscannedAllPlans" : 5,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 0,
"nChunkSkips" : 0,
"millis" : 0,
"indexBounds" : {
"a" : [
[
{
"$minElement" : 1
},
null
],
[
null,
{
"$maxElement" : 1
}
]
]
},
"server" : "my-laptop"
}