web-dev-qa-db-fra.com

Tri sur plusieurs champs mongoDB

J'ai une requête en mongo telle que je veux donner la préférence au premier champ, puis au deuxième champ.

Dis que je dois interroger tel que

db.col.find({category: A}).sort({updated: -1, rating: -1}).limit(10).explain()

J'ai donc créé l'index suivant

db.col.ensureIndex({category: 1, rating: -1, updated: -1})

Cela a fonctionné, il a simplement fallu scanner 10 autant d'objets que nécessaire, à savoir 10

Mais maintenant je dois interroger 

db.col.find({category: { $ne: A}}).sort({updated: -1, rating: -1}).limit(10)

J'ai donc créé l'index suivant

 db.col.ensureIndex({rating: -1, updated: -1})

mais cela conduit à la numérisation de l'ensemble du document et lorsque je crée 

 db.col.ensureIndex({ updated: -1 ,rating: -1})

Il scanne moins de nombre de documents

Je veux juste demander d'être clair sur le tri sur plusieurs champs et sur l'ordre à respecter pour le faire. En lisant les documents mongo-DB, il est clair que le champ sur lequel nous devons effectuer un tri doit être le dernier. C'est donc le cas que j'ai supposé dans ma requête $ ne ci-dessus. Est-ce que je fais quelque chose de mal?

24
Global Warrior

MongoDB query optimizer fonctionne en essayant différents plans pour déterminer quelle approche convient le mieux à une requête donnée. Le plan gagnant de ce modèle de requête est ensuite mis en cache pour les ~ 1 000 prochaines requêtes ou jusqu'à ce que vous fassiez un explain().

Pour comprendre quels plans de requête ont été considérés, vous devez utiliser explain(1) , par exemple:

db.col.find({category:'A'}).sort({updated: -1}).explain(1)

Le détail allPlans montrera tous les plans qui ont été comparés.

Si vous exécutez une requête peu sélective (par exemple, si de nombreux enregistrements correspondent à votre critère {category: { $ne:'A'}}), MongoDB trouvera peut-être plus rapidement des résultats à l'aide d'un BasicCursor (analyse de table) plutôt que de les faire correspondre à un index.

L'ordre des champs dans query ne fait généralement pas de différence pour la sélection d'index (il existe quelques exceptions aux requêtes d'intervalles). L'ordre des champs dans un sort affecte la sélection d'index. Si vos critères sort() ne correspondent pas à l'ordre d'index, les données de résultat doivent être triées à nouveau après l'utilisation de l'index (vous devriez voir scanAndOrder:true dans la sortie d'explication, le cas échéant).

Il est également intéressant de noter que MongoDB utilisera uniquement/ un index par requête (à l’exception de $ors).

Donc, si vous essayez d'optimiser la requête:

db.col.find({category:'A'}).sort({updated: -1, rating: -1})

Vous voudrez inclure les trois champs dans l'index:

db.col.ensureIndex({category: 1, updated: -1, rating: -1})

Pour votre information, si vous voulez forcer une requête particulière à utiliser un index (généralement inutile ou recommandé), il existe une option hint() que vous pouvez essayer.

27
Stennie

C'est vrai, mais vous avez deux niveaux de classement puisque vous effectuez un tri sur un index composé.

Comme vous l'avez remarqué, lorsque le premier champ de l'index correspond au premier champ de tri, cela a fonctionné et l'index a été vu. Cependant, lorsque vous travaillez en sens inverse, ce n'est pas le cas.

En tant que tel, selon vos propres obersvations, l'ordre à préserver est l'ordre d'interrogation des champs, du premier au dernier. L'analyseur Mongo peut parfois se déplacer dans les champs pour correspondre à un index, mais normalement, il essaiera simplement de faire correspondre le premier champ, sinon il l'ignorera.

1
Sammaye

essayez ce code, il triera d'abord les données en fonction du nom, puis gardera le 'nom' dans le détenteur de la clé. 

 var cursor = db.collection('vc').find({   "name" :   { $in: [ /cpu/, /memo/ ]   }     }, { _id: 0, }).sort( { "name":1  ,  "filter": 1 } );
0
Gajender Singh