2012-01-07 4 views
2

Je suis très confus pour l'instant, car j'ai deux colonnes indexées sur des tables séparées. L'une des tables, 'users', compte environ 400 000 entrées, et l'autre, 'posts', compte environ 8 000 000 entrées.RoR: Performance des champs indexés

Je sais que ces deux domaines sont indexés, et j'ai confirmé avec mon schéma:

add_index "users", ["username"], :name => "index_users_on_username", :unique => true 
add_index "posts", ["tag"], :name => "index_posts_on_tag", :unique => true 

Mais en quelque sorte, quand je lance ce qui suit, il faut compter entre 10 et 13 secondes:

User.find_by_username("mickeleh") 

et quand je cours essentiellement la même chose sur les messages, cela prend moins d'une seconde!

Post.find_by_tag("En-SKKB67Cg") 

Quelqu'un peut-il m'expliquer pourquoi cela pourrait se produire? Et/ou comment pourrais-je faire fonctionner ma méthode User.find_by_username plus rapidement?


Mise à jour:

j'ai couru une expliquer sur chacun des appels et je me suis le suivant:

mysql> explain SELECT `users`.* FROM `users` WHERE (lower(username) = 'mickeleh'); 
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra  | 
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+ 
| 1 | SIMPLE  | users | ALL | NULL   | NULL | NULL | NULL | 304548 | Using where | 
+----+-------------+----------+------+---------------+------+---------+------+--------+-------------+ 

et

mysql> explain SELECT `posts`.* FROM `posts` WHERE `posts`.`tag` = 'En-SKKB67Cg' LIMIT 1; 
+----+-------------+--------+-------+---------------------+---------------------+---------+-------+------+-------+ 
| id | select_type | table | type | possible_keys  | key     | key_len | ref | rows | Extra | 
+----+-------------+--------+-------+---------------------+---------------------+---------+-------+------+-------+ 
| 1 | SIMPLE  | posts | const | index_posts_on_tag | index_posts_on_tag | 258  | const | 1 |  | 
+----+-------------+--------+-------+---------------------+---------------------+---------+-------+------+-------+ 

Je ne sais pas exactement comment lire ce qui a été retourné, donc de l'aide avec être très apprécié.

J'ai aussi créé une nouvelle migration vers « reset » index sur la colonne de nom d'utilisateur des utilisateurs, comme suit:

remove_index :users, :column => :username 
add_index :users, :username, :unique => true 

ça n'a pas


Je viens de réaliser une chose cela pourrait causer le problème .. La table des utilisateurs a un champ qui est un ensemble sérialisé .. et je ne pense pas que cela causerait le problème. mais je pense que c'est possible.


MISE A JOUR FINAL

Ainsi, pour une raison quelconque, quand j'étais très développeur RoR novice, j'ai décidé que ce serait une bonne idée de remplacer la méthode 'find_by_username' avec le mien qui ferait en sorte qu'il a cherché des noms d'utilisateur ignorant le boîtier.

C'était assez ridicule .. comme je n'avais pas vraiment besoin de modifier la méthode d'origine pour obtenir la même réponse de requêtes différemment encapsulées.

Donc, la morale de l'histoire est de ne pas inclure la méthode suivante dans un modèle ....

def self.find_by_username(name) 
    User.where("lower(username) = '#{name.downcase}'")[0] 
end 

- visage paume -

+2

Avez-vous essayé d'exécuter expliquer sur la requête? (dans la console MySQL) –

+0

Je viens de lancer les explications et j'ai mis à jour ma question pour inclure les informations supplémentaires. – BananaNeil

Répondre

2
SELECT `users`.* FROM `users` WHERE (lower(username) = 'mickeleh'); 

Cette requête n'utilise pas d'index. Ça ne peut pas. Il récupèrera chaque nom d'utilisateur, le transformera en minuscules et vérifiera s'il est "mickeleh". La solution consisterait à s'assurer que les données sont en minuscules lorsqu'elles sont écrites dans la table, puis vous pouvez lire l'appel lower() et utiliser l'index.

Je sais où peu sur RoR, ou pourquoi il générerait les requêtes de cette manière, donc je ne peux pas vous aider là-bas.

+0

Donc, comme il se trouve, je peux exécuter .where ("username = 'MiCkElEH'") et j'obtiendrai toujours le même résultat .. (très rapidement). J'ai trouvé le problème (je vais mettre à jour ma question en deux secondes), mais je voulais juste vous faire savoir que je n'ai pas vraiment besoin de s'assurer que tout est mis en minuscules. – BananaNeil

2

Je ne suis pas sûr où l'appel à lower() est venu de (? Est-ce une requête à partir d'une validation unique), mais qui empêchera mysql d'utiliser un index, l'obligeant à faire une analyse complète de la table, comme le montre la sortie d'explication.

Questions connexes