2013-02-17 7 views
6

Ich habe eine Sammlung von Dokumenten mit einem MultiKey-Index definiert. Die Leistung der Abfrage ist jedoch ziemlich schlecht für nur 43 KB-Dokumente. Wird ~ 215ms für diese Anfrage als schlecht angesehen? Habe ich den Index richtig definiert, wenn nscanned 43902 ist (was den gesamten Dokumenten in der Sammlung entspricht)?MongoDB Index hilft nicht Abfrage mit MultiKey-Index

Dokument:

{ 
    "_id": { 
     "$oid": "50f7c95b31e4920008dc75dc" 
    }, 
    "bank_accounts": [ 
     { 
      "bank_id": { 
       "$oid": "50f7c95a31e4920009b5fc5d" 
      }, 
      "account_id": [ 
       "ff39089358c1e7bcb880d093e70eafdd", 
       "adaec507c755d6e6cf2984a5a897f1e2" 
      ] 
     } 
    ], 
    "created_date": "2013,01,17,09,50,19,274089", 
} 

Index:

{ "bank_accounts.bank_id" : 1 , "bank_accounts.account_id" : 1} 

Abfrage:

db.visitor.find({ "bank_accounts.account_id" : "ff39089358c1e7bcb880d093e70eafdd" , "bank_accounts.bank_id" : ObjectId("50f7c95a31e4920009b5fc5d")}).explain() 

Erklären:

{ 
    "cursor" : "BtreeCursor bank_accounts.bank_id_1_bank_accounts.account_id_1", 
    "isMultiKey" : true, 
    "n" : 1, 
    "nscannedObjects" : 43902, 
    "nscanned" : 43902, 
    "nscannedObjectsAllPlans" : 43902, 
    "nscannedAllPlans" : 43902, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 213, 
    "indexBounds" : { 
     "bank_accounts.bank_id" : [ 
      [ 
       ObjectId("50f7c95a31e4920009b5fc5d"), 
       ObjectId("50f7c95a31e4920009b5fc5d") 
      ] 
     ], 
     "bank_accounts.account_id" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ] 
    }, 
    "server" : "Not_Important" 
} 
+0

Eine Idee: Versuchen Sie, die Reihenfolge der Parameter zum Find umzudrehen, damit sie der durch den Index angegebenen Reihenfolge entsprechen. Wenn Sie nur eine Suche nach bank_id durchführen, verwendet das dann den Index? Dies sollte in der Reihenfolge erfolgen, die in secureindex angegeben ist. – WiredPrairie

+0

@WiredPrairie: Hinzufügen eines zweiten Index, der der Reihenfolge der Suchparameter entspricht, hat nicht geholfen. Und ja, wenn ich nur nach bank_id suche, wird ein Index verwendet (scannt aber immer noch 43K Dokumente). – Jason

+0

Könnten Sie einfach einen einzigen Index '{" bank_accounts.bank_id ": 1}' erstellen und nur die bank_id versuchen? Es ist sehr seltsam, dass es den Index nicht verwendet (Sie können den Index nach dem Test löschen). – WiredPrairie

Antwort

7

Ich sehe drei Faktoren im Spiel.

Zuerst, für Anwendungszwecke, stellen Sie sicher, dass $ elemMatch keine geeignetere Abfrage für diesen Anwendungsfall ist. http://docs.mongodb.org/manual/reference/operator/elemMatch/. Es scheint, als ob es schlecht wäre, wenn die falschen Ergebnisse aufgrund mehrerer Filialdokumente zurückkommen, die die Abfrage erfüllen.

Zweitens stelle ich mir vor, dass der hohe nscanned-Wert durch die unabhängige Abfrage jedes Feldwerts berücksichtigt werden kann. .find ({bank_accounts.bank_id: X}) gegen .find ({"bank_accounts.account_id": Y}). Sie können sehen, dass nscaned für die vollständige Abfrage in etwa gleich ist wie nscaned der größten Unterabfrage. Wenn der Indexschlüssel vollständig als Bereich ausgewertet würde, wäre dies nicht zu erwarten, aber ...

Drittens, die {"bank_accounts.account_id": [[{"$ minElement": 1}, {"$ Die Klausel maxElement ": 1}]]} des EXPLAIN-Plans zeigt, dass auf diesen Teil des Schlüssels kein Bereich angewendet wird.

Nicht wirklich sicher, warum, aber ich vermute, dass es etwas mit der Natur von account_id (ein Array innerhalb eines Filialdokuments innerhalb eines Arrays) zu tun hat. 200ms scheint ungefähr so ​​hoch zu sein.

könnte eine performante Dokument Organisation die account_id denormalize sein -> bank_id Beziehung im Subdokument und speichert:

{"bank_accounts": [ 
{ 
"bank_id": X, 
"account_id: Y, 
}, 
{ 
"bank_id": X, 
"account_id: Z, 
} 
]} 

statt: { "KONTEN": [{ "bank_id": X , „account_id: [Y, Z], }]}

Meine Tests unten zeigen, dass mit dieser Organisation, die Abfrageoptimierer zurück an der Arbeit bekommen und üben eine Reihe auf beiden Tasten:

> db.accounts.insert({"something": true, "blah": [{ a: "1", b: "2"} ] }) 
> db.accounts.ensureIndex({"blah.a": 1, "blah.b": 1}) 
> db.accounts.find({"blah.a": 1, "blah.b": "A RANGE"}).explain() 
{ 
    "cursor" : "BtreeCursor blah.a_1_blah.b_1", 
    "isMultiKey" : false, 
    "n" : 0, 
    "nscannedObjects" : 0, 
    "nscanned" : 0, 
    "nscannedObjectsAllPlans" : 0, 
    "nscannedAllPlans" : 0, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 0, 
    "indexBounds" : { 
     "blah.a" : [ 
      [ 
       1, 
       1 
      ] 
     ], 
     "blah.b" : [ 
      [ 
       "A RANGE", 
       "A RANGE" 
     ] 
    ] 
    } 
} 
+0

Zusätzlich zu den oben genannten, das ist, was Mongos FAQs auch vorschlagen - http://docs.mongodb.org/manual/faq/indexes/#how-can-i-effectively-use-indexes-strategy-for-attribute-lookups – Dayson