2012-04-11 6 views
2

Je cours une requête MongoDB assez ordinaire, rien de vraiment complexe ou spécial et je me demande si le temps qu'il faut (> 1 sec) est normal ou si quelque chose ne va pas avec mes index.Optimiser MongoDB Query ou Index

J'ai fourni un index pour cette requête spécifique et explain() me dit également qu'il est utilisé, mais il effectue un balayage complet de la collection à chaque fois et ralentit la page Web entière de> 1 seconde.

La requête:

db.tog_artikel.find({"art_filter":{"$exists":false},"$where":"this._id == this.art_hauptartikelnr"}) 

Expliqué:

> db.tog_artikel.find({"art_filter":{"$exists":false},"$where":"this._id == this.art_hauptartikelnr"}).explain() 
{ 
    "cursor" : "BtreeCursor art_filter_1_art_hauptartikelnr_1", 
    "nscanned" : 21306, 
    "nscannedObjects" : 21306, 
    "n" : 21306, 
    "millis" : 1180, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 
     "art_filter" : [ 
      [ 
       null, 
       null 
      ] 
     ], 
     "art_hauptartikelnr" : [ 
      [ 
       { 
        "$minElement" : 1 
       }, 
       { 
        "$maxElement" : 1 
       } 
      ] 
     ] 
    } 
} 

L'indice:

{ 
    "v": 1, 
    "key": { 
    "art_filter": 1, 
    "art_hauptartikelnr": 1 
    }, 
    "ns": "togshop.tog_artikel", 
    "background": true, 
    "name": "art_filter_1_art_hauptartikelnr_1" 
} 

Pourquoi la collection complète scannée à chaque fois? Pourquoi isMultiKey est faux et comment puis-je optimiser cette requête/index?

environnement est un serveur autonome, MongoDB 2.0.1, Linux 64 bits, accessible à partir de PHP w/php-mongo 1.2.6

Répondre

7

Pourquoi la collection complète scannée à chaque fois?

Ce n'est pas le cas. Il traverse l'indice:

"cursor" : "BtreeCursor art_filter_1_art_hauptartikelnr_1", 

Cela signifie que l'indice « art_filter_1_art_hauptartikelnr_1 » est utilisé pour satisfaire le $ existe condition.

Si ce filtre n'est pas très sélectif (c'est-à-dire si de nombreux enregistrements le satisfont), la requête prendra encore beaucoup de temps.

Pourquoi est isMultiKey faux

Il est faux, car aucun indice multitouche a été utilisé. Un index multi-clés est un index qui inclut des champs avec des tableaux en tant que valeurs. Cela n'a rien à voir avec l'index étant composite (c'est-à-dire ayant plusieurs champs).

$where":"this._id == this.art_hauptartikelnr" 

Votre deuxième condition est une expression Javascript, et un index ne peut pas être utilisé ici (depuis l'analyseur de requête ne comprend pas ce que vous faites). Même si c'était le cas, vous auriez besoin d'un index qui incluait également _id.

Comment puis-je optimiser cette requête/index?

Dénormez vos données pour avoir un nouveau champ "idIsHauptArtikelNr" avec les valeurs true ou false. Créer un index sur (art_filter, idIsHauptArtikelNr) et remplacer votre requête avec

{ art_filter :{ $exists :false}, idIsHauptArtikelNr : true } 
+2

Je vais ajouter que même si existe $ n'utilise un indice ces jours-ci, il doit encore marcher la plupart des b-arbre le satisfaire. En d'autres termes, vous avez réussi à utiliser deux des pires opérations ($ exists et $ where) dans une requête en termes de performances. –

+2

@RemonvanVliet: J'étais sur le point de le mentionner, mais alors je pensais qu'un $ existe: false devrait être relativement efficace sur un index non-sparse (alors qu'un $ existe: true doit marcher la plupart de l'arbre). YMMV en fonction de l'asymétrie des données. – Thilo

+1

Très vrai. $ exists: false est l'approche la plus efficace en raison de la sortie précoce des promenades dans les arbres. Quoi qu'il en soit, il est généralement préférable d'éviter $ existe si vous pouvez et $ où presque toujours;) –