2012-04-18 9 views
7

Los eventos de recopilación tienen userId y una matriz de eventos-- cada elemento de la matriz es un documento incrustado. Ejemplo:mongodb - no se utiliza el índice de fecha

{ 
    "_id" : ObjectId("4f8f48cf5f0d23945a4068ca"), 
    "events" : [ 
      { 
        "eventType" : "profile-updated", 
        "eventId" : "247266", 
        "eventDate" : ISODate("1938-04-27T23:05:51.451Z"), 
      }, 
      { 
        "eventType" : "login", 
        "eventId" : "64531", 
        "eventDate" : ISODate("1948-05-15T23:11:37.413Z"), 
      } 
    ], 
    "userId" : "junit-19568842", 

}

Uso de una consulta como la siguiente tofind eventos generados en los últimos 30 días:

db.events.find({ events : { $elemMatch: { "eventId" : 201, 
"eventDate" : {$gt : new Date(1231657163876) } } } } ).explain() 

plan de consulta muestra que el índice en "events.eventDate" se utiliza cuando los datos de prueba contiene un menor número de eventos (alrededor de 20):

{ 
    "cursor" : "BtreeCursor events.eventDate_1", 
    "nscanned" : 0, 
    "nscannedObjects" : 0, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : true, 
    "indexOnly" : false, 
    "indexBounds" : { 
      "events.eventDate" : [ 
        [ 
          ISODate("2009-01-11T06:59:23.876Z"), 
          ISODate("292278995-01--2147483647T07:12:56.808Z") 
        ] 
      ] 
    } 

}

Sin embargo, cuando hay un gran número de eventos (alrededor de 500), el índice no se utiliza:

{ 
    "cursor" : "BasicCursor", 
    "nscanned" : 4, 
    "nscannedObjects" : 4, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 

    } 

}

¿Por qué es el índice no se utiliza cuando hay una gran cantidad de eventos? ¿Puede ser cuando hay una gran cantidad de eventos, MongoDB encuentra que es eficiente simplemente escanear todos los elementos que usar el índice?

+0

¿Se queja de que el optimizador no usa el índice en una consulta que tardó 0ms en regresar? :) –

+0

El resultado de explicación anterior es de una colección de prueba. Con aproximadamente 20 millones de documentos, la consulta duró unos 8 segundos. – dsatish

+0

Las consultas de rango como ese pueden ser lentas si está consultando una parte importante de los documentos de la colección. Puede usar la sugerencia para forzar al índice a comparar la velocidad, pero imagino que será tan lento haciendo el escaneo de índice. Debe publicar una explicación de sus datos de producción, con y sin una pista. El caso es que si encuentra varios millones de documentos que coinciden, va a tomar un tiempo inspeccionarlos. –

Respuesta

11

El optimizador de consultas de MongoDB funciona de una manera especial. En lugar de calcular el costo de cierto plan de consulta, simplemente lanza todos los planes disponibles. El que devuelve primero se considera óptimo y se usará en el futuro.

La aplicación crece, los datos crecen y cambian, el plan óptimo puede no ser óptimo en algún momento. Entonces, mongo repite ese proceso de selección de consultas de vez en cuando.

Parece que en este caso concreto, el escaneo básico fue el más eficiente.

Enlace: http://www.mongodb.org/display/DOCS/Query+Optimizer

2

Usando $ pista para obligar a utilizar el índice "events.eventDate", los nscannedObjects es más de w/o el índice.

Pseudo código cuando se utiliza el índice:

for(all entries in index matching the criteria) { 
    get user object and scan to see if the eventId criteria is met 
} 

todas las entradas de índice que coinciden con los criterios -> cada evento es una entrada en el índice. Por lo tanto, la cantidad de entradas en el índice será mayor que la cantidad de usuarios. Supongamos que hay 4 objetos de usuario y un total de 7 eventos que coinciden con los criterios, el objeto de usuario se escanea 7 veces (para el ciclo se ejecuta 7 veces). Cuando el índice no se escanea, los 4 objetos del usuario se inspeccionan solo una vez. Entonces, al usar índice, la cantidad de veces que se explora el objeto del usuario es mayor que cuando no se utiliza el índice. ¿Es este entendimiento correcto?

db.events.find({ events : { $elemMatch: { "eventId" : 201, 
"eventDate" : {$gt : new Date(1231657163876) } } } } ) 
._addSpecial("$hint",{"events.eventDate":1}).explain() 

{ 
    "cursor" : "BasicCursor", 
    "nscanned" : 7, 
    "nscannedObjects" : 7, 
    "n" : 0, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 

} 
Cuestiones relacionadas