2013-05-09 15 views
6

Ho una raccolta MongoDB denominata post con 35 milioni di oggetti. La raccolta ha due indici secondari definiti come segue.Interrogazione intervallo lento su un indice multitasto

> db.post.getIndexKeys() 
[ 
    { 
     "_id" : 1 
    }, 
    { 
     "namespace" : 1, 
     "domain" : 1, 
     "post_id" : 1 
    }, 
    { 
     "namespace" : 1, 
     "post_time" : 1, 
     "tags" : 1 // this is an array field 
    } 
] 

mi aspetto la seguente query, che filtra semplicemente namespace e post_time, per l'esecuzione in un tempo ragionevole, senza la scansione di tutti gli oggetti.

>db.post.find({post_time: {"$gte" : ISODate("2013-04-09T00:00:00Z"), "$lt" : ISODate("2013-04-09T01:00:00Z")}, namespace: "my_namespace"}).count() 
7408 

Tuttavia, ci vuole MongoDB almeno dieci minuti per recuperare il risultato e, curiosamente, si riesce ad eseguire la scansione 70 milioni oggetti per fare il lavoro in base alla funzione explain.

> db.post.find({post_time: {"$gte" : ISODate("2013-04-09T00:00:00Z"), "$lt" : ISODate("2013-04-09T01:00:00Z")}, namespace: "my_namespace"}).explain() 
{ 
    "cursor" : "BtreeCursor namespace_1_post_time_1_tags_1", 
    "isMultiKey" : true, 
    "n" : 7408, 
    "nscannedObjects" : 69999186, 
    "nscanned" : 69999186, 
    "nscannedObjectsAllPlans" : 69999186, 
    "nscannedAllPlans" : 69999186, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 378967, 
    "nChunkSkips" : 0, 
    "millis" : 290048, 
    "indexBounds" : { 
     "namespace" : [ 
      [ 
       "my_namespace", 
       "my_namespace" 
      ] 
     ], 
     "post_time" : [ 
      [ 
       ISODate("2013-04-09T00:00:00Z"), 
       ISODate("292278995-01--2147483647T07:12:56.808Z") 
      ] 
     ], 
     "tags" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ] 
    }, 
    "server" : "localhost:27017" 
} 

La differenza tra il numero di oggetti e il numero di scansioni deve essere causata dalle lunghezze delle matrici di tag (che sono tutti uguali a 2). Tuttavia, non capisco perché il filtro post_time non faccia uso dell'indice.

Puoi dirmi cosa potrei mancare?

(Sto lavorando su una macchina di discesa con 24 core e 96 GB di RAM Sto usando MongoDB 2.2.3.).

+0

Lo spazio dei nomi ha una cardinalità molto bassa? – Sammaye

+0

Attualmente esiste un solo valore 'namespace', che è quello che sto usando. –

+0

Sì, perché MongoDB deve prima limitare il primo campo, quindi ottiene tutto "mio_namespace' e poi ottiene tutti i documenti tra quella data, ecc. Ecc., Prova a riordinare l'indice in modo che sia il primo post_time – Sammaye

risposta

3

trovato la mia risposta in questa domanda: Order of $lt and $gt in MongoDB range query

Il mio indice è un multitasto indice (su tags) e sto eseguendo una query di intervallo (su post_time). Apparently, MongoDB non può usare entrambi i lati dell'intervallo come filtro in questo caso, quindi sceglie semplicemente la clausola $gte, che viene prima. Poiché il mio limite inferiore è il valore più basso di post_time, MongoDB inizia la scansione di tutti gli oggetti.

Sfortunatamente, questa non è l'intera storia. Cercando di risolvere il problema, ho creato anche indici non multikey, ma MongoDB ha insistito sull'uso di quello cattivo. Questo mi ha fatto pensare che il problema fosse altrove. Infine, ho dovuto eliminare l'indice multikey e crearne uno senza il campo tags. Adesso va tutto bene.

+0

Dang Non l'ho mai saputo di '$ gt' e' $ lt' e miltikeys, bella scoperta! – Sammaye

+0

Usare cursor.hint potrebbe anche essere una soluzione per far mongodb usare l'altro indice (http://docs.mongodb.org/manual/reference/method/cursor.hint/#cursor.hint) – rudi

Problemi correlati