Улучшить поля запросов существуют в MongoDB - PullRequest
11 голосов
/ 26 января 2012

Я занимаюсь оценкой MongoDB для наших клиентов. В соответствии с требованиями нам нужно связать с некоторым набором переменных ent сущности *1001*.

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}})

В MongoDB Документы :

$ существует не очень эффективно, даже с индексом, и особенно. с {$ exist: true}, поскольку ему фактически придется сканировать все проиндексированные значения.

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

Ответы [ 4 ]

9 голосов
/ 26 января 2012

Вы можете изменить свою схему следующим образом:

{
  pairs:[
  {k: "a", v: 5775},
  {k: "b", v: "b1"},
  ]
}

Затем вы индексируете свой ключ:

db.people.ensureIndex({"pairs.k" : 1})

После этого вы сможете осуществлять поиск по точному совпадению:

db.ent.find({'pairs.k':"a"})

Если вы используете Sparse index и вашу текущую схему, предложенную @WesFreeman, вам нужно будет создать индекс для каждого ключа, который вы хотите найти.Это может повлиять на производительность записи или будет неприемлемым, если ваши ключи не статичны.

2 голосов
/ 26 января 2012

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

Если вы хотите / нуждаетесь в удобстве result.a, просто храните ключи где-нибудь индексируемым.*

вместо существующего:

db.ent.insert({a:5775, b:'b1'})

do

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"
            ]
        ]
    }
}
1 голос
/ 26 января 2012

Я думаю, что разреженный индекс является ответом на это, хотя вам понадобится индекс для каждого поля.http://www.mongodb.org/display/DOCS/Indexes#Indexes-SparseIndexes

Разреженные индексы должны помочь с $ Существуют: истинные запросы.

Даже если ваше поле не очень разреженное (то есть оно в основном установлено), оно не поможет вам в этом.много.

Обновление Наверное, я не прав.Похоже, что есть открытая проблема (https://jira.mongodb.org/browse/SERVER-4187), но $ существующие не использует разреженные индексы.Тем не менее, вы можете сделать что-то подобное с помощью 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" : {

}
}

Похоже, вы также можете использовать.подсказка ({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
            }
        ]
    ]
}
}
0 голосов
/ 03 июля 2013

Как насчет установки несуществующего поля в 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"
}
...