2012-04-18 13 views
7

Gli eventi di raccolta hanno userId e una serie di eventi: ogni elemento nell'array è un documento incorporato. Esempio:mongodb - la data dell'indice non viene utilizzata

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

}

utilizzando una query come quella qui sotto tofind eventi generati negli ultimi 30 giorni:

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

piano di query mostra che indice su "events.eventDate" viene utilizzato quando i dati del test contiene un minor numero di eventi (circa 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") 
        ] 
      ] 
    } 

}

Tuttavia, quando ci sono gran numero di eventi (circa 500), l'indice non viene utilizzato:

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

    } 

}

Perché non è l'indice utilizzato quando ci sono un sacco di eventi? Può essere quando c'è un gran numero di eventi, MongoDB trova che sia efficiente solo per scansionare tutti gli oggetti che usare l'indice?

+0

Ti stai lamentando che l'ottimizzatore non utilizza l'indice su una query che ha richiesto 0 ms per tornare? :) –

+0

L'output di spiegare sopra proviene da una raccolta di test. Con circa 20 milioni di documenti, la query ha richiesto circa 8 secondi. – dsatish

+0

Le query di intervallo come quelle possono essere lente se si sta interrogando una parte significativa dei documenti della raccolta. È possibile utilizzare il suggerimento per forzare l'indice a confrontare la velocità, ma immagino che sarà altrettanto lento a fare la scansione dell'indice. Dovresti pubblicare una spiegazione dai tuoi dati di produzione, con e senza un suggerimento. Il fatto è che, se trovi diversi milioni di documenti corrispondenti, ci vorrà del tempo per ispezionarli. –

risposta

11

Query Optimizer di MongoDB funziona in un modo speciale. Anziché calcolare il costo di un determinato piano di query, avvia solo tutti i piani disponibili. Qualunque ritorni primo è considerato ottimale e verrà utilizzato in futuro.

L'applicazione aumenta, i dati aumentano e cambiano, a un certo punto il piano ottimale potrebbe non essere ottimale. Quindi, mongo ripete quel processo di selezione delle query ogni tanto.

In questo caso concreto, la scansione di base è stata la più efficiente.

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

2

Utilizzando $ accenno alla forza per usare indice "events.eventDate", i nscannedObjects è più che w/o l'indice.

Pseudo codice quando si utilizza indice:

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

tutte le voci di indice che corrispondono ai criteri -> ogni evento è una voce nell'indice. Quindi il numero di voci nell'indice sarà maggiore del numero di utenti. Supponiamo che ci siano 4 oggetti utente e un totale di 7 eventi corrispondenti ai criteri, l'oggetto utente viene scansionato 7 volte (per il ciclo viene eseguito 7 volte). Quando l'indice non viene scansionato, tutti e 4 gli oggetti utente vengono ispezionati una sola volta. Quindi, usando l'indice, il numero di volte in cui l'oggetto utente viene scansionato è maggiore rispetto a quando non si utilizza l'indice. Questa comprensione è giusta?

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

} 
Problemi correlati