2012-04-18 3 views
7

Les événements de collection ont userId et un tableau d'événements - chaque élément du tableau est un document incorporé. Exemple:mongodb - index on date n'est pas utilisé

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

}

En utilisant une requête comme celle ci-dessous tofind événements générés par les 30 derniers jours:

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

Le plan de requête indique que l'index sur "events.eventDate" est utilisé lorsque les données de test contient moins d'événements (environ 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") 
        ] 
      ] 
    } 

}

Cependant, quand il y a un grand nombre d'événements (environ 500), l'indice n'est pas utilisé:

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

    } 

}

Pourquoi l'index ne sont pas utilisés quand il y a beaucoup d'événements? Peut être quand il ya un grand nombre d'événements, MongoDB trouve qu'il est efficace juste pour analyser tous les éléments que d'utiliser l'index?

+0

Vous vous plaignez que l'optimiseur n'utilise pas l'index sur une requête qui a pris 0ms pour retourner? :) –

+0

La sortie d'explication ci-dessus provient d'une collection de tests. Avec environ 20M documents, la requête a pris environ 8 secondes. – dsatish

+0

Les requêtes de plage de ce type peuvent être lentes si vous interrogez une partie importante des documents de la collection. Vous pouvez utiliser l'indice pour forcer l'index à comparer la vitesse, mais j'imagine que ce sera aussi lent de faire l'index. Vous devriez poster une explication à partir de vos données de production, avec ou sans indice. Le problème, c'est que si vous trouvez plusieurs millions de documents identiques, cela prendra du temps pour les inspecter. –

Répondre

11

L'optimiseur de requête de MongoDB fonctionne d'une manière spéciale. Plutôt que de calculer le coût de certains plans de requête, il ne fait que lancer tous les plans disponibles. Celui qui revient le premier est considéré comme optimal et sera utilisé dans le futur. L'application se développe, les données augmentent et les modifications, plan optimal peut ne pas devenir optimal à un certain point. Donc, mongo répète ce processus de sélection de requête de temps en temps.

Il semble que dans ce cas concret, le balayage de base soit le plus efficace.

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

2

En utilisant hint $ pour forcer à utiliser l'index "events.eventDate", les nscannedObjects est plus w/o l'indice.

Pseudo code lorsque l'index en utilisant:

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

toutes les entrées dans l'index correspondant aux critères -> chaque événement est une entrée dans l'indice. Le nombre d'entrées dans l'index sera donc supérieur au nombre d'utilisateurs. Dites qu'il y a 4 objets utilisateur et un total de 7 événements correspondant aux critères, l'objet utilisateur est analysé 7 fois (car la boucle est exécutée 7 fois). Lorsque l'index n'est pas analysé, les 4 objets utilisateur sont inspectés une seule fois. Donc, en utilisant index, le nombre de fois que l'objet utilisateur est analysé est plus que lorsque vous n'utilisez pas l'index. Est-ce que cette compréhension est juste?

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

}