2012-04-11 9 views
2

Ich bin eine ganz normale MongoDB Abfrage, nichts wirklich komplex oder speziell und ich frage mich, ob die Zeit (> 1 sec) normal ist oder wenn etwas mit meinen Indizes nicht stimmt.Optimieren MongoDB Abfrage oder Index

Ich habe einen Index für diese spezifische Abfrage und explain() auch sagt mir, es wird verwendet, aber es macht einen vollständigen Scan der Sammlung jedes Mal und verlangsamt die gesamte Webseite um> 1 Sek.

Die Abfrage:

db.tog_artikel.find({"art_filter":{"$exists":false},"$where":"this._id == this.art_hauptartikelnr"}) 

Erklärt:

> db.tog_artikel.find({"art_filter":{"$exists":false},"$where":"this._id == this.art_hauptartikelnr"}).explain() 
{ 
    "cursor" : "BtreeCursor art_filter_1_art_hauptartikelnr_1", 
    "nscanned" : 21306, 
    "nscannedObjects" : 21306, 
    "n" : 21306, 
    "millis" : 1180, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 
     "art_filter" : [ 
      [ 
       null, 
       null 
      ] 
     ], 
     "art_hauptartikelnr" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ] 
    } 
} 

Der Index:

{ 
    "v": 1, 
    "key": { 
    "art_filter": 1, 
    "art_hauptartikelnr": 1 
    }, 
    "ns": "togshop.tog_artikel", 
    "background": true, 
    "name": "art_filter_1_art_hauptartikelnr_1" 
} 

Warum die vollständige Sammlung jedes Mal gescannt wird? Warum ist isMultiKey falsch und wie kann ich diese Abfrage/Index optimieren?

Environment ist ein eigenständiger Server, MongoDB 2.0.1, 64-Bit-Linux, zugegriffen von PHP w/php-Mongo 1.2.6

Antwort

7

Warum die vollständige Sammlung jedes Mal gescannt wird?

Es ist nicht. Es wird durch den Index:

"cursor" : "BtreeCursor art_filter_1_art_hauptartikelnr_1", 

Dies bedeutet, dass der Index „art_filter_1_art_hauptartikelnr_1“ verwendet wird, die $ existiert Bedingung zu erfüllen.

Wenn dieser Filter nicht sehr selektiv ist (d. H. Es gibt viele Datensätze, die ihn erfüllen), wird die Abfrage immer noch sehr lange dauern.

Warum ist isMultiKey falsch

Es ist falsch, weil kein Multi_key Index verwendet wurde. Ein Multikey-Index ist ein Index, der Felder mit Arrays als Werte enthält. Es hat nichts damit zu tun, dass der Index zusammengesetzt ist (d. H. Mehrere Felder aufweist).

$where":"this._id == this.art_hauptartikelnr" 

Ihre zweite Bedingung ist ein JavaScript-Ausdruck, und ein Index kann hier nicht verwendet werden (da die Query Analyzer nicht versteht, was Sie tun). Selbst wenn dies der Fall wäre, würden Sie einen Index benötigen, der auch _id enthält.

Wie kann ich diese Abfrage/Index optimieren?

Denormalisieren Sie Ihre Daten, um ein neues Feld "idIsHauptArtikelNr" mit Werten wahr oder falsch zu haben. Erstellen Sie einen Index auf (art_filter, idIsHauptArtikelNr), und die Abfrage ersetzen mit

{ art_filter :{ $exists :false}, idIsHauptArtikelNr : true } 
+2

ich hinzufügen, dass werde, dass, obwohl $ existiert in diesen Tagen einen Index verwendet sie hat immer noch den größten Teil der B-Baum zu Fuß zu erfülle es. Mit anderen Worten, Sie haben zwei der schlechtesten Operationen ($ exists und $ where) in einer Abfrage in Bezug auf die Leistung verwendet. –

+2

@RemonvanVliet: Ich war dabei, das zu erwähnen, aber dann dachte ich, ein $ exists: false sollte relativ effizient auf einem nicht-spärlichen Index sein (während ein $ existiert: true muss den größten Teil des Baumes gehen). YMMV abhängig von Datenschräglauf. – Thilo

+1

Sehr wahr. $ exists: false ist der effizientere Ansatz aufgrund der frühen Baumspaziergänge. Egal, es ist im Allgemeinen besser zu vermeiden $ existiert, wenn Sie können und $ wo ziemlich immer;) –