2012-01-25 14 views
10

Sono in corso con la stima di MongoDB per i nostri clienti. In base ai requisiti, è necessario associare un gruppo variabile di coppie nome-valore alla coppia ent.Esistono campi di query migliori in MongoDB

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

Dopo questo ho bisogno tua ricerca intensamente ent per presenza di campi:

db.ent.find({'a':{$exists:true}}) 
db.ent.find({'c':{$exists:false}}) 

Per MongoDB docs:

$ esiste non è molto efficiente anche con un indice, e l'ESP. con {$ exists: true} dato che dovrà effettivamente effettuare la scansione di tutti i valori indicizzati.

può esperti vi fornirà modo più efficiente (anche con lo spostamento del paradigma) per far fronte velocemente con variare a coppie nome-valore

+0

un'occhiata a: http://www.mongodb.org/display/DOCS/Using+Multikeys+to+Simulate+a+Large+Number+of+ Gli indici – Dewfy

risposta

9

È possibile ridisegnare lo schema come questo:

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

Poi si consente di ordinare la chiave:

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

Dopo questo si sarà in grado di cercare per corrispondenza esatta:

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

Se si va con Indice sparse e lo schema corrente, proposto da @WesFreeman, è necessario creare un indice su ogni chiave che si desidera cercare. Può influire sulle prestazioni di scrittura o non sarà accettabile se le tue chiavi non sono statiche.

+0

Molto interessante. Ma come posso capire quale documento è stato associato alla chiave 'a' (proprietaria di 'a'). C'è qualcosa come '$ parent ({pairs.k: a})'? – Dewfy

+0

@Dewfy mongodb restituisce sempre il documento di livello root (anche se si esegue una ricerca per array incorporato), quindi non è necessario cercare il genitore, sarà restituito dalla query. Provalo e vedrai. –

+0

+1 Nuova riprogettazione. L'indice sparse potrebbe essere più veloce, se le chiavi sono davvero sparse, ma come dici tu ci sono degli svantaggi. –

1

penso che un indice di scarsa è la risposta a questo, anche se avrete bisogno di un indice per ogni campo. http://www.mongodb.org/display/DOCS/Indexes#Indexes-SparseIndexes

Gli indici sparsi dovrebbero aiutare con $ esiste: query true.

Anche se il tuo campo non è davvero scarso (il che significa che è quasi tutto impostato), non ti aiuterà molto.

Aggiornamento Credo di essermi sbagliato. Sembra che ci sia un problema aperto (https://jira.mongodb.org/browse/SERVER-4187) ancora che $ exists non usi indici sparsi. Tuttavia, si può fare qualcosa di simile con find e ordinare, che sembra che utilizza correttamente l'indice di scarsa:

db.ent.find({}).sort({a:1}); 

Ecco una dimostrazione completa della differenza, utilizzando i valori di esempio:

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

Si noti che find({}).sort({a:1}) utilizza l'indice (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 
      } 
     ] 
    ] 
} 
} 

E find({a:{$exists:true}}) fa una scansione completa:

> 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" : { 

} 
} 

Sembra che sia possibile utilizzare anche .hint ({a: 1}) per forzare l'utilizzo dell'indice.

> 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

in realtà l'ultimo 'spiega' mostra il mio problema - nessun indice usato per trovare il documento, ma sarebbe usato intensivamente. Ma comunque grazie per la risposta – Dewfy

+0

La mia prima query con find() e sort() usa l'indice. –

+0

Aggiunto un altro commento su hint(). –

2

Basta riprogettare lo schema in modo che sia una query indicizzabile. Il tuo caso d'uso è infatti analogo al primo esempio di applicazione dato in MongoDB The Definitive Guide.

Se si desidera/necessario la comodità di result.a, è sufficiente memorizzare le chiavi in ​​un punto indicizzabile.

al posto dell'esistente:

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

fare

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

Ecco quindi una query indicizzabile:

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" 
      ] 
     ] 
    } 
} 

o se siete sempre suscettibili di interrogare anche per valore:

db.ent.insert({ 
    a:5775, 
    b:'b1', 
    index: [ 
     {name: 'a', value: 5775}, 
     {name: 'b', value: 'b1'} 
    ] 
}) 

che è anche una query indicizzabile:

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" 
      ] 
     ] 
    } 
} 
+0

nice way (+1), ma sembra un po 'ridondante – Dewfy

0

Come sull'impostazione del non esiste campo per null? Quindi puoi interrogarli con {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() 

ecco l'output:

{ 
    "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" 
} 
+1

Le query "$ ne" non possono utilizzare gli indici. http://docs.mongodb.org/manual/faq/indexes/#using-ne-and-nin-in-a-query-is-slow-why – Megawolt