2012-01-25 21 views
10

Estoy en progreso con la estimación de MongoDB para nuestros clientes. Según los requisitos, necesitamos asociarnos con alguna entidad ent conjunto variable de pares nombre-valor.Mejorar los campos de consulta en 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'}) 

Después de esto necesito su búsqueda intensiva ent para la presencia de campos:

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

por MongoDB docs:

$ existe no es muy eficiente, incluso con un índice y esp. con {$ exists: true} ya que efectivamente tendrá que escanear todos los valores indexados.

Puede expertos no proporcionar de manera más eficiente (incluso con el cambio de paradigma) para hacer frente rápidamente con variar pares nombre-valor

+0

vistazo a: http://www.mongodb.org/display/DOCS/Using+Multikeys+to+Simulate+a+Large+Number+of+ Índices – Dewfy

Respuesta

9

Puede rediseñar el esquema de la siguiente manera:

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

A continuación, la indexación de su clave:

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

Después de esto usted será capaz de buscar por coincidencia exacta:

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

En caso de que vaya con El índice disperso y su esquema actual, propuesto por @WesFreeman, deberá crear un índice en cada tecla que desee buscar. Puede afectar el rendimiento de escritura o no será aceptable si sus claves no son estáticas.

+0

Muy interesante. Pero ¿cómo puedo averiguar qué documento se asoció con la clave 'a' (posee por 'a'). ¿Hay algo como '$ parent ({pairs.k: a})'? – Dewfy

+0

@Dewfy mongodb siempre devuelve el documento de nivel de raíz (incluso si busca por matriz incrustada), por lo que no es necesario buscar padre, se devolverá por la consulta. Solo pruébalo y lo verás. –

+0

+1 Buen rediseño. El índice disperso puede ser más rápido, si las claves son realmente dispersas, pero como usted dice que hay inconvenientes. –

1

Creo que un índice disperso es la respuesta a esto, aunque se necesita de una índice para cada campo. http://www.mongodb.org/display/DOCS/Indexes#Indexes-SparseIndexes

Los índices dispersos deberían ayudar con $ exists: consultas verdaderas.

Aún así, si su campo no es realmente escaso (lo que significa que está configurado en su mayoría), no lo ayudará mucho.

Actualización Supongo que estoy equivocado. Parece que hay un problema abierto (https://jira.mongodb.org/browse/SERVER-4187) aún que $ existe no usa índices dispersos. Sin embargo, se puede hacer algo como esto con el hallazgo y tipo, que parece que correctamente utiliza el índice disperso:

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

He aquí una demostración completa de la diferencia, usando sus valores de ejemplo:

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

Tenga en cuenta que find({}).sort({a:1}) utiliza el índice (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 
      } 
     ] 
    ] 
} 
} 

Y find({a:{$exists:true}}) realiza un escaneo completo:

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

} 
} 

Parece que también puede usar .hint ({a: 1}) para obligarlo a usar el índice.

> 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

En realidad, la última 'explicación' muestra mi problema: no se utilizan índices para localizar el documento, pero se usaría de manera intensiva. Pero de todos modos, gracias por la respuesta – Dewfy

+0

Mi primera consulta con find() y sort() utiliza el índice. –

+0

Se ha agregado otro comentario sobre la sugerencia(). –

2

Simplemente rediseñe su esquema de modo que sea una consulta indexable. Su caso de uso es de hecho análogo a la primera aplicación de ejemplo dada en MongoDB The Definitive Guide.

Si desea/necesita la conveniencia de result.a solo guarde las llaves en algún lugar indexable.

en lugar del existente:

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

hacer

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

Eso es entonces una consulta indexable:

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 si alguna vez probable que consultar también por el valor:

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

Eso también es una consulta indexable:

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), pero parece un poco redundante – Dewfy

0

Cómo sobre la configuración de la no existe campo para null? Luego puede consultarlos 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() 

Aquí está la salida:

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

Las consultas "$ ne" no pueden usar índices. http://docs.mongodb.org/manual/faq/indexes/#using-ne-and-nin-in-a-query-is-slow-why – Megawolt

Cuestiones relacionadas