2012-03-27 11 views
18

Oggi ho notato che l'ordine in cui vengono dati gli operatori $ lt e $ gt sembra importare in MongoDB 2.0.2.

Ho un database di giochi. "player" è un array di due stringhe che rappresentano entrambi i giocatori, "endedAtMS" è un timestamp al termine del gioco. Ho creato questo indice:

db.games.ensureIndex({player:1,endedAtMS:-1}) 

Per ottenere 30 dei miei giochi, terminate in un certo intervallo di tempo, in ordine di tempo i giochi in cui finito, mi fanno:

db.games.find({ "player" : "Stefan" , 
       "endedAtMS" : { "$lt" : 1321284969946 , 
           "$gt" : 1301284969946}}). 
     sort({endedAtMS:-1}). 
     limit(30). 
     explain() 

{ 
    "cursor" : "BtreeCursor player_1_endedAtMS_-1", 
    "nscanned" : 30, 
    "nscannedObjects" : 30, 
    "n" : 30, 
    "millis" : 0, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : true, 
    "indexOnly" : false, 
    "indexBounds" : { 
     "player" : [ 
      [ 
       "Stefan", 
       "Stefan" 
      ] 
     ], 
     "endedAtMS" : [ 
      [ 
       1321284969946, 
       -1.7976931348623157e+308 
      ] 
     ] 
    } 
} 

Tutto sembra funziona bene Tuttavia quando cambio l'ordine di $ lt e $ gt nella query precedente ottengo questo:

db.games.find({ "player" : "Stefan" , 
       "endedAtMS" : { "$gt":1301284969946, 
           "$lt" : 1321284969946}}). 
     sort({endedAtMS:-1}). 
     limit(30). 
     explain() 

{ 
    "cursor" : "BtreeCursor player_1_endedAtMS_-1", 
    "nscanned" : 126, 
    "nscannedObjects" : 126, 
    "n" : 30, 
    "millis" : 1, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : true, 
    "indexOnly" : false, 
    "indexBounds" : { 
     "player" : [ 
      [ 
       "Stefan", 
       "Stefan" 
      ] 
     ], 
     "endedAtMS" : [ 
      [ 
       1.7976931348623157e+308, 
       1301284969946 
      ] 
     ] 
    } 
} 

Come si può vedere 126 documenti necessitino di scansione per ottenere i 30 documenti per il risultato. Se dai un'occhiata all'indiceBounds nell'output di spiegazione sembra che solo il primo operatore sia utilizzato per limitare lo spazio di ricerca nell'indice.

Cosa mi manca? Perché Mongo utilizza solo un operatore per limitare lo spazio di ricerca?

+0

Buona scoperta! Aspettiamo 10gen ragazzi :) –

+0

Ho incontrato lo stesso problema (bug?) Con 2.0.3. Vedi [la mia domanda] (http://stackoverflow.com/questions/9776383/why-are-any-objects-being-scanned-here). 10gen - ti amiamo - ti preghiamo di spiegarlo! –

+0

Mi chiedo quanto presto i 10gen ragazzi riescono a capirlo ... hanno la sensazione che ciò richiederebbe il 2.0.4 – Baba

risposta

8

Questo è un problema noto. La risposta breve è che ha a che fare con il fatto che viene utilizzato un indice multikey ("player" è un array) e l'indice non può essere vincolato su entrambi i limiti superiore e inferiore.

Questo è spiegato in modo più dettagliato nel caso Jira: https://jira.mongodb.org/browse/SERVER-4155 - "Index bound errato?"

C'è un ticket Jira aperto per migliorare questo comportamento: https://jira.mongodb.org/browse/SERVER-4180 - "Indexbounds errati selezionati per una query dell'intervallo di date (regressione)" che è previsto per essere rilasciato nella versione 2.1.2 (questa versione è soggetta a modifiche). Si prega di votare per questo!

+1

Grazie per la risposta, tuttavia non sono sicuro di aver capito perché l'indice non può essere confinato a causa dell'array. Se si aggiunge una voce nell'indice per ciascun elemento nell'array, non dovrebbe importare. In ogni caso, limitare l'indice di entrambe le parti aiuterebbe solo in parte. Se Mongo sceglie ancora la parte sbagliata del limite per iniziare la ricerca, deve cercare 65 documenti nel mio esempio sopra. Immagino che il problema principale qui sia quello di scegliere l'estremità corretta per iniziare la ricerca, quindi l'altro indice associato non è affatto necessario per trovare i 30 documenti per il risultato con solo 30 scansioni. – StefanMK

+1

Prendi l'esempio dal caso Jira: https://jira.mongodb.org/browse/SERVER-4155: Se i limiti dell'indice [2, 9] sono utilizzati per a, il documento non verrà restituito. Per evitare ciò, viene utilizzato solo il primo limite. Il primo limite viene scelto per comodità, non viene eseguita alcuna logica.Come menzionato nella mia risposta sopra, stiamo lavorando per migliorare questo comportamento. – Marc

+1

Ah ok, grazie. – StefanMK