web-dev-qa-db-fra.com

$ skip et $ limit dans le cadre d'agrégation

Quand j'ai lu le document, j'ai trouvé les notes suivantes:

Quand un tri $ précède immédiatement une limite $ dans le pipeline, l'opération $ sort ne conserve que les n premiers résultats au fur et à mesure de sa progression, où n est la limite spécifiée, et MongoDB n'a besoin que de stocker n éléments en mémoire. Cette optimisation s'applique toujours lorsque allowDiskUse est vrai et que les n éléments dépassent la limite de mémoire d'agrégation.

Si j'ai raison à ce sujet, cela ne s'applique que lorsque j'utilise ensemble $ sort et $ limit comme

db.coll.aggregate([
    ...,
    {$sort: ...},
    {$limit: limit},
    ...
]);

Cependant, je pense que la plupart du temps nous aurions

db.coll.aggregate([
    ...,
    {$sort: ...},
    {$skip: skip},
    {$limit: limit},
    ...
]);

Question 1: Cela signifie-t-il que la règle ci-dessus ne s'applique pas si j'utilise $ skip ici?

Je pose cette question parce que théoriquement MongoDB peut toujours calculer les enregistrements --- n supérieurs et améliorer les performances en triant uniquement les enregistrements --- n supérieurs. Je n'ai cependant trouvé aucun document à ce sujet. Et si la règle ne s'applique pas,

Question 2: Dois-je modifier ma requête comme suit pour améliorer les performances?

db.coll.aggregate([
    ...,
    {$sort: ...},
    {$limit: skip + limit},
    {$skip: skip},
    {$limit: limit},
    ...
]);

MODIFIER : Je pense que mon cas d'utilisation rendrait la question ci-dessus plus logique. J'utilise la fonction de recherche de texte fournie par MongoDB 2.6 pour rechercher des produits. Je suis inquiet si l'utilisateur saisit un mot clé très courant comme "rouge", il y aura trop de résultats renvoyés. Je cherche donc de meilleures façons de générer ce résultat.

EDIT2: Il s'avère que le dernier code ci-dessus est égal à

db.coll.aggregate([
    ...,
    {$sort: ...},
    {$limit: skip + limit},
    {$skip: skip},
    ...
]);

Ainsi, nous pouvons toujours utiliser ce formulaire pour appliquer la règle top n.

35
yaoxing

Comme il s'agit d'une requête de recherche de texte dont nous parlons, la forme la plus optimale est la suivante:

db.collection.aggregate([
    { "$match": {
        "$text": { "$search": "cake tea" }
    }},
    { "$sort": { "score": { "$meta": "textScore" } },
    { "$limit": skip + limit },
    { "$skip": skip }
])

Le raisonnement sur la réserve de mémoire des résultats de "tri" supérieurs ne fonctionnera que dans ses propres "limites" pour ainsi dire et cela ne sera pas optimal pour quoi que ce soit au-delà de quelques "pages" raisonnables de données.

Au-delà de ce qui est raisonnable pour la consommation de mémoire, l'étape supplémentaire aura probablement un effet négatif plutôt que positif.

Ce sont vraiment les limites pratiques des capacités de recherche de texte disponibles pour MongoDB sous la forme actuelle. Mais pour tout ce qui est plus détaillé et nécessitant plus de performances, comme c'est le cas avec de nombreuses solutions SQL "texte intégral", il vaut mieux utiliser une solution de recherche de texte externe "sur mesure".

49
Neil Lunn