2017-05-16 1 views
1

Ich habe rund 75.000 Dokumente in einer Sammlung.Mongo finden Abfrage dauert 2 Minuten

Die Gesamtgröße der Datenbank beträgt ca. 45 GB.
Von den 75.000 Dokumenten sind etwa 45.000 von jeweils 900 KB (etwa 42 GB) und die restlichen Dokumente etwa 120 KB.

Jedes Dokument ist einer custId ObjectId in einer anderen Sammlung zugeordnet und hat eine timestamp, beide indiziert.

Jetzt muss ich die Dokumente für eine bestimmte custId für letzten Monat abrufen. Die Zählung ist ungefähr 5500 Dokumente. Diese custId hat die kleinen Dokumente mit einer Größe von jeweils etwa 120 KB.

Im Anschluss an meine Anfrage:

db.mycollection.find(
{ 
    custId:ObjectId("CUST_OBJECT_ID_HERE"), 
    timestamp:{$gte:one_month_ago_date, $lt:current_date} 
}).sort({timestamp:-1}) 

noch die Abfrage dauert 2 Minuten, um alle Datensätze zu holen. Liegt es an der Anzahl der Dokumente oder an der Größe der größeren Dokumente? Gibt es eine Möglichkeit, das zu beheben?

HINWEIS: Es dauert 2 Minuten, wenn die Abfrage von Nodejs ausgelöst wird. Wenn ich es auf Mongo Shell feuere, kommt es schnell zurück, aber es könnte sein, weil es nur die ersten 50 Datensätze holt. Als ich .count() an die Abfrage der Mongo-Shell anschloss, dauerte es 2 Minuten, um mit der Zählung zurückzukehren.

Update:
Indexing Details:

"wiredTiger" : { 
    "nindexes" : 3, 
    "totalIndexSize" : 2396160, 
    "indexSizes" : { 
     "_id_" : 1138688, 
     "custId_1" : 598016, 
     "timestamp_1" : 659456 
    } 
} 

Output Erklären: (mit Art)

{ 
    "queryPlanner" : { 
     "plannerVersion" : 1, 
     "namespace" : "mydb.mycollection", 
     "indexFilterSet" : false, 
     "parsedQuery" : { 
      "$and" : [ 
       { 
        "custId" : { 
         "$eq" : ObjectId("CUST_OBJECT_ID_HERE") 
        } 
       }, 
       { 
        "timestamp" : { 
         "$lt" : ISODate("2017-05-15T14:20:04.393Z") 
        } 
       }, 
       { 
        "timestamp" : { 
         "$gte" : ISODate("2017-04-15T14:20:04.393Z") 
        } 
       } 
      ] 
     }, 
     "winningPlan" : { 
      "stage" : "FETCH", 
      "filter" : { 
       "custId" : { 
        "$eq" : ObjectId("CUST_OBJECT_ID_HERE") 
       } 
      }, 
      "inputStage" : { 
       "stage" : "IXSCAN", 
       "keyPattern" : { 
        "timestamp" : 1 
       }, 
       "indexName" : "timestamp_1", 
       "isMultiKey" : false, 
       "isUnique" : false, 
       "isSparse" : false, 
       "isPartial" : false, 
       "indexVersion" : 1, 
       "direction" : "backward", 
       "indexBounds" : { 
        "timestamp" : [ 
         "(new Date(1494858004393), new Date(1492266004393)]" 
        ] 
       } 
      } 
     }, 
     "rejectedPlans" : [ 
      { 
       "stage" : "SORT", 
       "sortPattern" : { 
        "timestamp" : -1 
       }, 
       "inputStage" : { 
        "stage" : "SORT_KEY_GENERATOR", 
        "inputStage" : { 
         "stage" : "FETCH", 
         "filter" : { 
          "$and" : [ 
           { 
            "timestamp" : { 
             "$lt" : ISODate("2017-05-15T14:20:04.393Z") 
            } 
           }, 
           { 
            "timestamp" : { 
             "$gte" : ISODate("2017-04-15T14:20:04.393Z") 
            } 
           } 
          ] 
         }, 
         "inputStage" : { 
          "stage" : "IXSCAN", 
          "keyPattern" : { 
           "custId" : 1 
          }, 
          "indexName" : "custId_1", 
          "isMultiKey" : false, 
          "isUnique" : false, 
          "isSparse" : false, 
          "isPartial" : false, 
          "indexVersion" : 1, 
          "direction" : "forward", 
          "indexBounds" : { 
           "custId" : [ 
            "[ObjectId('CUST_OBJECT_ID_HERE'), ObjectId('CUST_OBJECT_ID_HERE')]" 
           ] 
          } 
         } 
        } 
       } 
      } 
     ] 
    }, 
    "serverInfo" : { 
     "host" : "test-machine", 
     "port" : 27017, 
     "version" : "3.2.12", 
     "gitVersion" : "REMOVED_BY_OP" 
    }, 
    "ok" : 1 
} 
+0

ist es wegen der Sorte. Es muss das Ganze entweder in den Speicher oder auf die Festplatte laden. Wegen der Größe der Datenbank wird es wahrscheinlich auf die Festplatte geladen, die langsam ist. Sie könnten versuchen, nur die Eigenschaften anzugeben, die Sie abrufen müssen, wodurch es leichter wird und es möglicherweise in den Speicher passt. Ich denke, es wird auch nur 1 Index verwenden, wenn die Sortierung verwendet wird, und es wird den Timestamp-Index auswählen und den custId-Index ignorieren. Sie könnten versuchen, einen zusammengesetzten Index für custId und timestamp hinzuzufügen. – PeteG

+0

Verwenden Sie auch Paginierung, wenn Sie nicht alle Dokumente benötigen –

+0

Welche Indizes haben Sie für diese Sammlung? hast du versucht mongodb zu erklären? Wie funktioniert diese Abfrage ohne Sortierung innerhalb der Mongo Shell? – Astro

Antwort

1

diesen Index Versuchen:

db.mycollection.createIndex({custId:1,timestamp:1}, {background:true}) 
3

Dies ist, was Index für ist!

Erstellen Sie Index für Timestamp und CustId (Verbundindex mit beiden wäre am effizientesten) und Sie sind ganz in Ordnung. Da durch Zeitstempel des Sortierens, in Verbindung Index, stellen den Zeitstempel der erste (um Angelegenheiten)


Dies ist der Code für die Erstellung von Verbundindex in mongo:

const mongoose = require('mongoose'); 
const Schema = mongoose.Schema; 

const userSchema = new Schema({ 
    //... 
}); 

userSchema.index({timestamp: 1, custId: 1}); 

mongoose.model('User', userSchema); 
module.exports = userSchema; 
+0

Können Sie bitte den zusammengesetzten Index näher erläutern? Wie bereits erwähnt, habe ich "custId" und "timestamp" indiziert, aber keinen zusammengesetzten Index. Wenn Sie erwähnen können, wie es mit Mungo gemacht werden kann, wäre das noch besser. –

+0

@DushyantBangal Bitte beachten Sie den @Astro answear-Index für die Erstellung einer Verbindung (Kombination mehrerer Schlüssel). Bitte lesen Sie Mongoose Dokumentation für zusammengesetzte Index: https: // docs.mongodb.com/manual/indexes/# Indizes-CompoundKeys –

+0

@DushyantBangal - Compound-Index ist ein Index, der mehr Felder auf einmal zuordnen. Grundsätzlich ist es die beste Option, wenn Sie schnell alle diese Felder in der Abfrage auswählen möchten. Die innere Funktionalität ist nicht so einfach, aber solange Sie es nicht mit mehr als einem Feld sortieren und Sie es immer mit allen Feldern in der Abfrage suchen, funktioniert es gut. – libik

0

Die Antworten oben sind alle völlig richtig. Ich werde nur meine 2 Cent reinlegen. Diese Antwort hängt stark von dem Speicher ab, der Ihnen zur Verfügung steht, und wenn die Informationen, die Sie zurückgeben müssen, "Echtzeit" sind oder die Informationen in irgendeiner Weise zwischengespeichert werden können.

Mongodb ist berüchtigt für Speicherbenutzung. (Ich mag Mongodb, aber Gedächtnis ist die Achillesferse). Zweitens wie oben erwähnt alles, was Sie tun können, um Abfrageergebnisse zu verbessern vor die Abfrage erfolgt ist ein großes Plus in der Zeit, liest und Kernnutzung. Wenn es um die Speicherung von Dokumenten geht, können Sie einen korrekt eingerichteten Redis-Cache finden, der Ihnen hilft, die Reaktionszeit zu verkürzen.

Offensichtlich erfordert dies Speicher und in Ihrem Fall eine Balance (einschließlich Load Balancing). Es ist die richtige Mischung aus Speicher, Geschwindigkeit und Festplattennutzung (auch wenn es SSD ist), die Ihnen helfen wird, diese Anfragen an die Anforderungen des Systems anzupassen.

Hoffe, dass hilft ein bisschen.