2015-03-17 8 views
6

ich eine Webseite haben, die MongoDB zum Speichern und Abrufen verschiedener Messungen verwendet. Irgendwann plötzlich wurde meine Webseite so träge, dass sie unbrauchbar wurde. Es stellt sich heraus, meine Datenbank ist der Schuldige.MongoDB: Langsam Abfrage, auch mit dem Index

Ich suchte und habe keine Lösung für mein Problem gefunden, und ich entschuldige mich, da ich MongoDB ziemlich neu bin und mir im Moment die Haare rausziehe.

Version von MongoDB verwende ich ist 2.4.6, auf VM Machine mit 20GB RAM, die Ubuntu Server 12.04 läuft. Es gibt keine Replik oder Sharding-Einrichtung.

Erstens ich meine Profilierung Ebene auf 2 gesetzt und es zeigte die langsamste Abfrage:

db.system.profile.find().sort({"millis":-1}).limit(1).pretty() 
{ 
     "op" : "query", 
     "ns" : "station.measurement", 
     "query" : { 
       "$query" : { 
         "e" : { 
           "$gte" : 0 
         }, 
         "id" : "180" 
       }, 
       "$orderby" : { 
         "t" : -1 
       } 
     }, 
     "ntoreturn" : 1, 
     "ntoskip" : 0, 
     "nscanned" : 3295221, 
     "keyUpdates" : 0, 
     "numYield" : 6, 
     "lockStats" : { 
       "timeLockedMicros" : { 
         "r" : NumberLong(12184722), 
         "w" : NumberLong(0) 
       }, 
       "timeAcquiringMicros" : { 
         "r" : NumberLong(5636351), 
         "w" : NumberLong(5) 
       } 
     }, 
     "nreturned" : 0, 
     "responseLength" : 20, 
     "millis" : 6549, 
     "ts" : ISODate("2015-03-16T08:57:07.772Z"), 
     "client" : "127.0.0.1", 
     "allUsers" : [ ], 
     "user" : "" 
} 

ich, dass bestimmte Abfrage mit .explain lief() und sieht aus wie, verwendet es Index, wie es sollte, aber es braucht zu lange. Ich lief auch die gleiche Abfrage auf meinen anderen, drastisch schwächer Server und sput aus den Ergebnissen wie ein Champion in einer Sekunde.

> db.measurement.find({"id":"180", "e":{$gte:0}}).sort({"t":-1}).explain() 
{ 
     "cursor" : "BtreeCursor id_1_t_-1_e_1", 
     "isMultiKey" : false, 
     "n" : 0, 
     "nscannedObjects" : 0, 
     "nscanned" : 660385, 
     "nscannedObjectsAllPlans" : 1981098, 
     "nscannedAllPlans" : 3301849, 
     "scanAndOrder" : false, 
     "indexOnly" : false, 
     "nYields" : 7, 
     "nChunkSkips" : 0, 
     "millis" : 7243, 
     "indexBounds" : { 
       "id" : [ 
         [ 
           "180", 
           "180" 
         ] 
       ], 
       "t" : [ 
         [ 
           { 
             "$maxElement" : 1 
           }, 
           { 
             "$minElement" : 1 
           } 
         ] 
       ], 
       "e" : [ 
         [ 
           0, 
           1.7976931348623157e+308 
         ] 
       ] 
     }, 
     "server" : "station:27017" 
} 

Als nächstes sah ich in Indizes von Messung Sammlung und es sah gut zu mir:

> db.measurement.getIndexes() 
[ 
     { 
       "v" : 1, 
       "key" : { 
         "_id" : 1 
       }, 
       "ns" : "station.measurement", 
       "name" : "_id_" 
     }, 
     { 
       "v" : 1, 
       "key" : { 
         "t" : 1 
       }, 
       "ns" : "station.measurement", 
       "name" : "t_1" 
     }, 
     { 
       "v" : 1, 
       "key" : { 
         "id" : 1, 
         "d" : 1, 
         "_id" : -1 
       }, 
       "ns" : "station.measurement", 
       "name" : "id_1_d_1__id_-1" 
     }, 
     { 
       "v" : 1, 
       "key" : { 
         "id" : 1, 
         "t" : -1, 
         "e" : 1 
       }, 
       "ns" : "station.measurement", 
       "name" : "id_1_t_-1_e_1" 
     }, 
     { 
       "v" : 1, 
       "key" : { 
         "id" : 1, 
         "t" : -1, 
         "e" : -1 
       }, 
       "ns" : "station.measurement", 
       "name" : "id_1_t_-1_e_-1" 
     } 
] 

Hier ist auch der Rest der Informationen meiner Sammlung:

> db.measurement.stats() 
{ 
     "ns" : "station.measurement", 
     "count" : 157835456, 
     "size" : 22377799512, 
     "avgObjSize" : 141.77929395027692, 
     "storageSize" : 26476834672, 
     "numExtents" : 33, 
     "nindexes" : 5, 
     "lastExtentSize" : 2146426864, 
     "paddingFactor" : 1.0000000000028617, 
     "systemFlags" : 0, 
     "userFlags" : 0, 
     "totalIndexSize" : 30996614096, 
     "indexSizes" : { 
       "_id_" : 6104250656, 
       "t_1" : 3971369360, 
       "id_1_d_1__id_-1" : 8397896640, 
       "id_1_t_-1_e_1" : 6261548720, 
       "id_1_t_-1_e_-1" : 6261548720 
     }, 
     "ok" : 1 
} 

Ich habe versucht, einen neuen Index hinzuzufügen, die ganze Datenbank zu reparieren, neu zu indizieren. Was mache ich falsch? Ich schätze jede Hilfe sehr, da mir die Ideen schnell ausgingen.

UPDATE 1:

Ich habe zwei Indizes wie von Neil Lunn vorgeschlagen, sind nur einige der Anfragen viel schneller:

{ 
       "v" : 1, 
       "key" : { 
         "id" : 1, 
         "e" : 1, 
         "t" : -1 
       }, 
       "ns" : "station.measurement", 
       "name" : "id_1_e_1_t_-1", 
       "background" : true 
     }, 
     { 
       "v" : 1, 
       "key" : { 
         "id" : 1, 
         "e" : -1, 
         "t" : -1 
       }, 
       "ns" : "station.measurement", 
       "name" : "id_1_e_-1_t_-1", 
       "background" : true 
     } 

Ergebnisse Ich habe interessant sind (nicht sicher, obwohl sie sind relevant)

Next zwei Abfragen unterscheidet sich von "id" nur. Bitte beachten Sie, dass jede Abfrage einen anderen Index verwendet, warum? Soll ich ältere löschen?

> db.measurement.find({"id":"119", "e":{$gte:0}}).sort({"t":-1}).explain() 
{ 
     "cursor" : "BtreeCursor id_1_t_-1_e_1", 
     "isMultiKey" : false, 
     "n" : 840747, 
     "nscannedObjects" : 840747, 
     "nscanned" : 1047044, 
     "nscannedObjectsAllPlans" : 1056722, 
     "nscannedAllPlans" : 1311344, 
     "scanAndOrder" : false, 
     "indexOnly" : false, 
     "nYields" : 4, 
     "nChunkSkips" : 0, 
     "millis" : 3730, 
     "indexBounds" : { 
       "id" : [ 
         [ 
           "119", 
           "119" 
         ] 
       ], 
       "t" : [ 
         [ 
           { 
             "$maxElement" : 1 
           }, 
           { 
             "$minElement" : 1 
           } 
         ] 
       ], 
       "e" : [ 
         [ 
           0, 
           1.7976931348623157e+308 
         ] 
       ] 
     }, 
     "server" : "station:27017" 
} 

> db.measurement.find({"id":"180", "e":{$gte:0}}).sort({"t":-1}).explain() 
{ 
     "cursor" : "BtreeCursor id_1_e_1_t_-1", 
     "isMultiKey" : false, 
     "n" : 0, 
     "nscannedObjects" : 0, 
     "nscanned" : 0, 
     "nscannedObjectsAllPlans" : 0, 
     "nscannedAllPlans" : 45, 
     "scanAndOrder" : true, 
     "indexOnly" : false, 
     "nYields" : 0, 
     "nChunkSkips" : 0, 
     "millis" : 0, 
     "indexBounds" : { 
       "id" : [ 
         [ 
           "180", 
           "180" 
         ] 
       ], 
       "e" : [ 
         [ 
           0, 
           1.7976931348623157e+308 
         ] 
       ], 
       "t" : [ 
         [ 
           { 
             "$maxElement" : 1 
           }, 
           { 
             "$minElement" : 1 
           } 
         ] 
       ] 
     }, 
     "server" : "station:27017" 
} 

Könnte das Problem wo anders sein? Was könnte diese plötzliche "Trägheit" verursachen? Ich habe mehrere andere Sammlungen, wo Abfragen auch plötzlich langsamer sind.

Oh, und eine andere Sache. Auf diesem anderen Server habe ich dieselben Indizes wie hier, bevor ich neue hinzugefügt habe. Ja, die Sammlung ist ein bisschen kleiner, aber es ist mehrmals schneller.

+2

Gut als eine Frage gebildet. Es scheint, dass Sie mehr "t" -Einträge scannen als "e". Versuchen Sie als Experiment, den Index und die Abfragefolge zu ändern, um die geordnete Hervorhebung auf "e" vor "t" zu setzen. Änderungsdokumente schlagen vor, dass dies das Ergebnis nicht ändern sollte, aber Ihre Ergebnisse wären interessant, um zu sehen, ob es einen Unterschied gibt. –

+0

Interessanter Vorschlag, danke! Ich werde neue Indizes (id_1_e_1_t_-1 und id_1_e_-1_t_-1) hinzufügen und Sie bald über die Ergebnisse informieren, da der Aufbau von Indizes einige Zeit in Anspruch nehmen wird. – Denis

+0

Hey, ich habe diese Indizes erfolgreich erstellt und mit einigen Abfragen getestet. Ich aktualisierte meine Frage mit den Ergebnissen :) – Denis

Antwort

0

Dann war hier Punkt in der Auswahl der Index- und Abfrageordnung.

Wenn Sie Ihre frühere Ausgabe von .explain() betrachten, werden Sie sehen, dass es einen "min/max" -Bereich für das Element "t" in Ihrem Ausdruck gibt. Indem Sie "bis ans Ende" der Auswertung verschieben, lassen Sie andere Filterelemente zu, die für den Gesamtausdruck wichtiger sind (bestimmen Sie weniger mögliche Übereinstimmungen von "e" als Hauptfaktor, bevor Sie "t" im Grunde "alles" scannen) .

Es ist ein bisschen DBA, aber in der NoSQL-Welt glaube ich, dass dies ein Programmiererproblem wird.

Sie müssen im Wesentlichen Ihren "kürzesten Übereinstimmungspfad" entlang der ausgewählten Schlüssel erstellen, um den effektivsten Scan zu erhalten. Deshalb werden die veränderten Ergebnisse viel schneller ausgeführt.