2013-07-12 7 views
0

Le système que je développe actuellement sur, utilise MongoDB 2.4.4MongoDB trouver lent avec regex

J'ai une collection d'utilisateurs.

Il y a un indice combiné: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} J'ai aussi essayé avec des indices simples, sans augmentation de la performance

Le système contient les enregistrements de test 400.000.

La requête (Java debug de org.springframework.data.mongodb.core.query.Query):

{ "LASTNAME" : { "$regex" : "^Schm"}}, 
    Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 ,"LASTNAME" : 1}, 
    Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} 

dans 16ms.That est effectue fantastique.

Cette requête n'apparaît pas dans la console MongoDB (aucune information de débogage à afficher ici).

Mais, j'aime chercher ne commence pas seulement, il devrait également être insensible à la casse.

la requête:

{ "LASTNAME" : { "$regex" : "^Schm" , "$options" : "i"}}, 
    Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 , "LASTNAME" : 1}, 
    Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} 

effectue au sein de 897ms. C'est inacceptable lent.

Console Mongo montre ceci:

query: { query: { LASTNAME: /^Schm/i }, 
    orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1, CITY:1, STATUS: 1 } 
} cursorid:1252405545564528 ntoreturn:25 ntoskip:0 nscanned:297651 
keyUpdates:0 numYields: 1 locks(micros) r:1391715 nreturned:25 reslen:4422 897ms 

Comme on peut le voir. Ce n'est pas le problème scanAndOrder qui pointe sur les problèmes d'index.

Ensuite, j'ai essayé de le résoudre la prochaine façon ce qui correspond le plus à des scénarios (inséré de l'utilisateur, minuscules et majuscules), mais c'est aussi plus lent. Mon attente était, qu'il effectue trois fois aussi longtemps que la première requête.

la requête:

{ "$or" : [ { "LASTNAME" : { "$regex" : "^Schm"}} , { "LASTNAME" : { "$regex" : "^schm"}} , { "LASTNAME" : { "$regex" : "^SCHM"}}]}, 
    Fields: { "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1 , "LASTNAME" : 1}, 
    Sort: { "LASTNAME" : 1 , "FIRSTNAME" : 1 , "EMAIL" : 1 , "CITY" : 1 , "STATUS" : 1} 

effectue au sein de 1300ms. Rien d'autre à dire.

console MongoDB:

query: { query: { $or: [ { LASTNAME: /^Schm/ }, { LASTNAME: /^schm/ }, { LASTNAME: /^SCHM/ } ] }, 
    orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1, CITY: 1, STATUS: 1 } 
} cursorid:43560166842085 ntoreturn:25 ntoskip:0 nscanned:297651 
keyUpdates:0 numYields: 1 locks(micros) r:1531168 nreturned:25 reslen:4422 1300ms 

Alors, comment puis-je recherche insensible à la casse qui a presque la vitesse de la première recherche? Maximal 150ms!

+0

En note, j'ai enlevé les balises Java puisque cette question est seulement liée à Mongo, pas Java –

+0

Pouvez-vous s'il vous plaît poster le 'explain()' pour votre requête '$ or' –

+0

Je ne sais pas comment , en utilisant Spring MongoTemplate. Actuellement, je pense à passer à mongo-java-driver ... – Nabor

Répondre

7

Dès que vous ajoutez une insensibilité à la casse, vous ne pouvez plus utiliser d'index. Il s'agit d'un problème de conception important lors de la création d'une application qui doit prendre en charge la recherche. Pour remédier à cela, vous devez stocker une version déjà en minuscule du nom de famille dans un autre champ, et effectuer une requête dans ce sens (traduisant évidemment toutes vos requêtes de recherche en minuscules avant de les passer à Mongo).

Modifier

Il ressemble à la recherche de texte a été ajouté à 2,4. Lisez à ce sujet here et voir si cela va faire ce que vous avez besoin.En guise de remarque, si vous êtes vraiment préoccupé par les performances (qui, à en juger par votre question, vous semblez être), vous devriez vraiment reconsidérer la recherche par rapport à votre moteur de stockage de données. Envisagez un autre moteur de recherche comme ElasticSearch (ou un index Lucene simple) pour empêcher le trafic de recherche de votre magasin de données principal.

+1

"Dès que vous ajoutez l'insensibilité à la casse, vous ne pouvez pas utilisez plus longtemps un index "<- +1 pour cela. C'est comme si les gens se plaignaient que leur requête SQL soit lente aux dates lorsqu'ils utilisent 'trunc()'. – fge

+0

Mais alors, pourquoi la solution est-elle si lente? – Nabor

+0

@Nabor Indépendamment de la raison pour laquelle votre solution '$ or' est si lente (je crois que c'est parce que Mongo est en train de retomber sur un index depuis que vous lui avez donné 3" racines "possibles), vous devriez vous demander si ça ne vaut pas votre temps quand même. Allez-vous vraiment construire une requête '$ or' avec chaque permutation de casing valide pour chaque lettre dans une requête, afin d'éviter une recherche insensible à la casse? Ce ne sera pas plus rapide. Index ou non. –