3 votes

MongoDB $lookup (agrégation) et $projet en fonction des performances

Je faisais des tests de performance sur une grande agrégation mongo scripts et j'ai remarqué que lorsque je déplace la ligne de projet de

           "$lookup":{
        "from": "metrics",
        "as":   "metrics",
        "let": {"userId": "$_id"},
        "pipeline": {
        {"$match":{"$expr": {"$in": {"$$userId","$ownerIds"}}}},
  ----> {"$project": {"fieldName": 1, "ownerIds": 1, "auth0Cache": 1}},
},
},

a

      "$lookup":{
        "from": "metrics",
        "as":   "metrics",
        "let": {"userId": "$_id"},
        "pipeline": {
---->   {"$project": {"fieldName": 1, "ownerIds": 1, "auth0Cache": 1}},
        {"$match":{"$expr": {"$in": {"$$userId","$ownerIds"}}}},

},
},

Cela a fait sauter les performances. Il a fonctionné 2 à 3 fois plus vite. Il est logique que lorsque vous limitez les données, puisque cette collection est importante, elle devrait s'exécuter plus rapidement, mais je n'ai pas trouvé de documentation à ce sujet. Quelqu'un sait-il pourquoi il s'agit d'un changement important et peut-il m'expliquer ce qui se passe exactement et me fournir des informations supplémentaires à ce sujet ? Merci d'avance.

0voto

user20042973 Points 1641

Il y a trop peu d'informations dans la question actuellement pour tirer des conclusions définitives. Comme @Tornike Skhulukhia suggère dans le commentaire en partageant l'intégralité .explain("executionStats") pour cette agrégation nous donnerait beaucoup plus de visibilité sur ce qui peut se passer.

Une chose qui semble potentiellement suspecte ici, sur la base du peu qui a été partagé, est l'utilisation de crochets ( { y } ) pour définir le pipeline . Normalement, il s'agit d'un tableau permettant de prévoir une séquence d'étapes d'agrégation. En effet, mongoplayground se plaint lorsque des accolades sont utilisées. . Il s'agit probablement d'une erreur de copier/coller lors de la création de la question, d'autant plus qu'il y a la même faute de frappe avec l'attribut $in mais il est certain que si le pilote/langage que vous utilisez n'a pas respecté la pipeline jusqu'à la première étape qui peut aider à expliquer ce qui se passe. Notez qu'il est Il est possible, dans certaines situations, de transmettre un seul document (représentant l'unique étape d'agrégation) à la .aggregate() elle-même plutôt qu'un tableau comme d'habitude, voici une petite démonstration de terrain de jeu prouvant qu'une telle structure y fonctionne avec succès. Des manigances de ce type ne sont donc pas à exclure et de plus amples informations seraient utiles.

Si je lis un peu entre les lignes, il semble que vous essayez d'améliorer les performances d'un pipeline d'agrégation. Bien que, encore une fois, il n'y ait pas assez d'informations pour affirmer quoi que ce soit avec certitude, je suggérerais de simplifier cette définition $lookup . Votre stade actuel est défini comme suit :

  {
    "$lookup": {
      "from": "metrics",
      "as": "metrics",
      "let": {
        "userId": "$_id"
      },
      "pipeline": [
        {
          "$match": {
            "$expr": {
              "$in": [
                "$$userId",
                "$ownerIds"
              ]
            }
          }
        },
        {
          "$project": {
            "fieldName": 1,
            "ownerIds": 1,
            "auth0Cache": 1
          }
        }
      ],

    }
  }

Cela peut être simplifié en utilisant le localField / foreignField syntaxe au moins comme suit :

  {
    "$lookup": {
      "from": "metrics",
      "as": "metrics",
      localField: "_id",
      foreignField: "ownerIds",
      "pipeline": [
        {
          "$project": {
            "fieldName": 1,
            "ownerIds": 1,
            "auth0Cache": 1
          }
        }
      ],

    }
  }

Démonstrations sur le terrain de jeu de avant y après .

Cette modification peut permettre à la base de données de mieux exploiter un indice de { ownerIds: 1 } sur le metrics collection.

La dernière chose que je mentionnerais est liée à l'utilisation de $project . Il est vrai que c'est généralement une bonne idée de réduire la quantité de données traitées le plus tôt possible. Mais l'utilisation de la projection devrait être réservée à la fin d'un pipeline (ou sous-pipeline), juste comme un moyen de transformer les résultats dans le format que vous désirez. La base de données se chargera automatiquement de déterminer quels champs sont nécessaires au pipeline et limitera ces données de manière optimale chaque fois que cela sera possible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X