2016-10-07 5 views
6

Ich habe eine Sammlung namens "logTransaction". Ich möchte die Ergebnisse erhalten, wie Sie im angehängten Bild sehen können.MongoDB AggregationOutput längere Reaktionszeit

output

logTransaction viele Felder hat aber die für dieses Bild verwendeten sind:

customer, environment, firstTime, lastTime, integrationIds[] (eine Transaktion mehr als 1 Integration haben kann), transactionStatus (FERTIG, UNFINISHED, FAILED)

Ich verwende AggregationOutput für dieses Ergebnis, aber es dauert mehr als 30 Sekunden, die viel länger ist (denke ich) als die Menge von Daten, die ich habe. Ich frage mich nur, ob ich das verbessern kann, indem ich das ändere, was ich bereits habe oder sollte ich es total ändern. Welche Art der Indexierung sollte ich verwenden, um die Dinge noch schneller zu machen?

Ich verwende MongoDB und Grails. Meine aktuelle Methode sieht wie folgt aus:

def myCustomAggregation(integrations, timestamp_lt, timestamp_gt, cust, env) { 
    def currentRequest = RequestContextHolder.requestAttributes 

    def customer = cust ?: currentRequest?.session?.customer 
    def environment = env ?: currentRequest?.session?.environment 

    //$match 
    DBObject matchMap = new BasicDBObject('integrationIds', new BasicDBObject('$in', integrations.collectAll { it?.baselineId })) 
    matchMap.put("firstTimestamp", new BasicDBObject('$lte', timestamp_lt as Long).append('$gte', timestamp_gt as Long)) 
    matchMap.put("customer",customer) 
    matchMap.put("environment",environment) 
    DBObject match = new BasicDBObject('$match',matchMap); 

    //$group1 
    Map<String, Object> dbObjIdMap1 = new HashMap<String, Object>(); 
    dbObjIdMap1.put('integrationId', '$integrationIds'); 
    dbObjIdMap1.put('transactionStatus', '$transactionStatus'); 
    DBObject groupFields1 = new BasicDBObject("_id", new BasicDBObject(dbObjIdMap1)); 
    groupFields1.put('total', new BasicDBObject('$sum', 1)); 
    DBObject group1 = new BasicDBObject('$group', groupFields1); 

    //$group2 
    DBObject groupFields2 = new BasicDBObject("_id", '$_id.integrationId'); 
    groupFields2.put('total_finished', 
     new BasicDBObject('$sum', new BasicDBObject('$cond', [ 
      new BasicDBObject('$eq', ['$_id.transactionStatus', 'FINISHED']), '$total', 0 
     ])) 
    ); 
    groupFields2.put('total_unfinished', 
     new BasicDBObject('$sum', new BasicDBObject('$cond', [ 
      new BasicDBObject('$eq', ['$_id.transactionStatus', 'UNFINISHED']), '$total', 0 
     ])) 
    ); 
    groupFields2.put('total_failed', 
     new BasicDBObject('$sum', new BasicDBObject('$cond', [ 
      new BasicDBObject('$eq', ['$_id.transactionStatus', 'FAILED']), '$total', 0 
     ])) 
    ); 
    DBObject group2 = new BasicDBObject('$group', groupFields2); 
    // This taking more than 30 seconds. Its too much for the amount of data I have in Database. 
    AggregationOutput output = db.logTransaction.aggregate(match,group1,group2) 
    return output.results() 
} 

Edit:

ich eine Verbindung Index erstellt als HoefMeistert vorgeschlagen:

db.logTransaction.createIndex({integrationIds: 1, firstTimestamp: -1, customer: 1, environment: 1}) 

Aber wenn ich auf dieses Aggregat erklären:

db.logTransaction.explain().aggregate([ 
    { $match: {integrationIds: {$in: ["INT010","INT011","INT012A","INT200"]}, "firstTimestamp": { "$lte" : 1476107324000 , "$gte" : 1470002400000}, "customer": "Awsome_Company", "environment": "PROD"}}, 
    { $group: { _id: {"integrationId": '$integrationIds', "transactionStatus": '$transactionStatus'}, total: {$sum: 1}}}, 
    { $group: { _id: "$_id.integrationId", "total_finished": {$sum: {$cond: [{$eq: ["$_id.transactionStatus", "FINISHED"]}, "$total", 0]}}, "total_unfinished": {$sum: {$cond: [{$eq: ["$_id.transactionStatus", "UNFINISHED"]}, "$total", 0]}}, "total_failed": {$sum: {$cond: [{$eq: ["$_id.transactionStatus", "FAILED"]}, "$total", 0]}}}} 
]); 

Ich bekomme diesen wintingPlan immer noch jedes Mal: ​​

"winningPlan" : { 
       "stage" : "CACHED_PLAN", 
       "inputStage" : { 
        "stage" : "FETCH", 
        "filter" : { 
         "$and" : [ 
           { 
            "environment" : { 
              "$eq" : "PROD" 
            } 
           }, 
           { 
            "integrationIds" : { 
             "$in" : [ 
              "INT010", 
              "INT011", 
              "INT012A", 
              "INT200" 
             ] 
            } 
           } 
         ] 
        }, 
        "inputStage" : { 
          "stage" : "IXSCAN", 
          "keyPattern" : { 
           "tenant" : 1, 
           "firstTimestamp" : -1 
          }, 
          "indexName" : "customer_1_firstTimestamp_-1", 
          "isMultiKey" : false, 
          "isUnique" : false, 
          "isSparse" : false, 
          "isPartial" : false, 
          "indexVersion" : 1, 
          "direction" : "forward", 
          "indexBounds" : { 
           "customer" : [ 
            "[\"Awsome_Company\", \"Awsome_Company\"]" 
           ], 
           "firstTimestamp" : [ 
            "[1476107324000.0, 1470002400000.0]" 
           ] 
          } 
        } 
       } 
     }, 

Aktuelle Indizes für die Sammlung in Entwicklung env. und die Geschwindigkeit ist gut im Vergleich zu vor, aber wenn Zeitspanne größer als 1 Woche, habe ich noch bekommen sockettimeoutexception (3 Minuten):

"customer_1_firstTimestamp_-1" : 56393728, 
"firstTimestamp_-1_customer_1" : 144617472, 
"integrationIds_1_firstTimestamp_-1" : 76644352, 
"integrationId_1_firstTimestamp_-1" : 56107008, 
"transactionId_1_firstTimestamp_-1" : 151429120, 
"firstTimestamp_1" : 56102912, 
"transactionId_1" : 109445120, 
"integrationIds_1_firstTimestamp_-1_customer_1_environment_1" : 247790976 
+0

Niemand kann helfen hier draußen? – Yonetmen

+1

Haben Sie eine Abfrage erstellt, die der von Grails ähnelt, um MongoDb abzufragen? Der erste Schritt, um herauszufinden, ist, ob es sich um ein Grails-Problem oder eine unoptimierte Abfrage handelt. Haben Sie in MongoDb einige Spalten indexiert, um die Abfrage zu beschleunigen? – elixir

Antwort

3

Welche Indizes Sie haben derzeit? Wenn ich an Ihrer Aggregation aussehen, dass Sie einen Indizes auf dem Feld haben Sie paßt auf:

  • integrationIds
  • firstTimestamp
  • Kunde
  • Umgebung

Nach dem ersten (Match) Stage-Indizes sind nicht mehr relevant. Wie von elixir gefragt, wie ist die Leistung in Shell/Editor? Ist es auch langsam dort? Wenn ja, versuche die "langsame" Bühne zu finden.

Update: Sie können auch die Aggregation Pipeline optimizer helfen, das Spiel zu einem einzigen $and Spiel Rewrite ;-)

{ $match: {integrationIds: {$in: ["INT010","INT011","INT012A","INT200"]}, "firstTimestamp": { "$lte" : 1476107324000 , "$gte" : 1470002400000}, "customer": "Awsome_Company", "environment": "PROD"}} 

an: me

{ $match: { $and : [ 
     {integrationIds: {$in: ["INT010","INT011","INT012A","INT200"]}}, 
     {"firstTimestamp": { "$lte" : 1476107324000 , "$gte" : 1470002400000}}, 
     {"customer": "Awsome_Company"}, 
     {"environment": "PROD"}] 
    } 
+0

Hallo HoefMeistert, meinst du, dass man für jedes Feld einen Index oder für alle nur einen zusammengesetzten Index haben sollte? – oxyt

+0

Nun, das hängt wirklich davon ab, dass Sie "andere" Indizierung benötigen. Wenn Sie nur diese Felder abfragen, können Sie einen zusammengesetzten Index erstellen. Sie müssen über Ihren zusammengesetzten Index nachdenken. ex mit einem Komponentenindex von {integrationIds: 1, firstTimestamp: 1, customer: 1, environment: 1}. Der Index wird verwendet bei der Abfrage von: integrationIds, integrationIds && firstTimestamp, integrationIds && firstTimestamp && customer, integrationIds && firstTimestamp && customer && Umgebung. Wenn Sie nach "customer" suchen, wird der Index nicht verwendet. Siehe https://docs.mongodb.com/v3.2/core/index-compound/ – HoefMeistert

+0

. Weitere Informationen zur Indexüberschneidung finden Sie hier: https: // docs. mongodb.com/v3.2/core/index-intersection/#index-intersection-compound-indexes – HoefMeistert

Verwandte Themen