2013-05-09 12 views
6

Ich habe eine MongoDB-Sammlung namens post mit 35 Millionen Objekte. Die Sammlung hat zwei Sekundärindizes, die wie folgt definiert sind.Langsame Bereichsabfrage auf einem Multi-Kachel-Index

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

Ich erwarte, dass die folgende Abfrage, die einfach filtert durch namespace und post_time, in einer angemessenen Zeit laufen, ohne dass alle Objekte zu scannen.

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

Allerdings dauert es MongoDB mindestens zehn Minuten das Ergebnis und neugierig abzurufen, sie verwaltet 70 Millionen Objekte scannen den Job nach der explain Funktion zu tun.

> 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" 
} 

Der Unterschied zwischen der Anzahl der Objekte und der Anzahl der Scans müssen von den Längen der Markierungsarrays hervorgerufen werden (die alle gleich 2 sind). Trotzdem verstehe ich nicht, warum post_time Filter den Index nicht nutzt.

Können Sie mir sagen, was ich fehlen könnte?

(Ich arbeite an einer Abfahrt Maschine mit 24 Kernen und 96 GB RAM Ich bin mit MongoDB 2.2.3.).

+0

Hat Namespace eine sehr geringe Mächtigkeit bekam? – Sammaye

+0

Momentan gibt es nur einen eindeutigen 'Namespace'-Wert, den ich verwende. –

+0

Ja, deshalb, MongoDB auf dem ersten Feld zuerst beschränken müssen, so dass es alle 'my_namespace' bekommt und dann erhält alle Dokumente zwischen diesem Datum, etc etc, versuchen, den Index-Neuordnungs so die post_time erste ist – Sammaye

Antwort

3

in dieser Frage meine Antwort gefunden: Order of $lt and $gt in MongoDB range query

Mein Index ist ein Multi_key Index (auf tags) und ich führe eine Bereichsabfrage (auf post_time). Apparently, MongoDB kann nicht beiden Seiten des Bereichs als Filter in diesem Fall benutzen, so nimmt es nur die $gte Klausel, die zuerst kommt. Da meine untere Grenze der niedrigste post_time Wert ist, beginnt MongoDB alle Objekte zu scannen.

Leider ist dies nicht die ganze Geschichte. Um das Problem zu lösen, habe ich nicht-multikey-Indizes erstellt, aber MongoDB bestand darauf, das schlechte zu verwenden. Das ließ mich denken, dass das Problem woanders war. Schließlich musste ich den mikey Index fallen lassen und einen ohne das tags Feld erstellen. Alles ist jetzt gut.

+0

Dang das wusste ich nie über '$ gt' und' $ lt' und miltikey, netter Fund! – Sammaye

+0

Die Verwendung von cursor.hint könnte auch eine Lösung sein, damit mongodb den anderen Index verwendet (http://docs.mongodb.org/manual/reference/method/cursor.hint/#cursor.hint) – rudi

Verwandte Themen