2010-03-30 7 views
3

Je suis relativement nouveau chez RoR. Dans mon contrôleur, je répète chaque tuple dans la base de données. Pour chaque table, pour chaque colonne que j'appelaisRuby on Rails: Model.all.each vs find_by_sql ("SELECT * FROM modèle"). Chaque?

SomeOtherModel.find_by_sql("SELECT column FROM model").each {|x| #etc }

qui fonctionnait assez bien. Quand je plus tard changé cela

Model.all(:select => "column").each {|x| #etc }

la boucle commence à peu près la même vitesse, mais ralentit rapidement à quelque chose comme 100 fois plus lent que la la commande find_by_sql. Ces appels devraient être identiques, donc je ne sais vraiment pas ce qui se passe.

Je sais que ces appels ne sont pas les plus efficaces mais ce n'est qu'une étape intermédiaire et je l'optimiserai plus une fois que cela fonctionnera correctement. Donc, pour clarifier: Pourquoi, dans le monde, appeler Model.all.each fonctionne-t-il beaucoup plus lentement que l'utilisation de find_by_sql.each?

Merci!

Répondre

7

Les deux appels effectuent le même appel SQL, de sorte qu'ils doivent tous les deux avoir à peu près la même vitesse. Model.all passe par un niveau supplémentaire d'indirection. Je pense que Rails dans all recueille toutes les lignes de la connexion DB, puis appelle cette collection en tant que param à une autre méthode qui boucle sur cette collection et crée les objets du modèle. En find_by_sql il fait tout cela en 1 méthode. Peut-être que c'est un peu plus rapide. Quelle est la taille de votre ensemble de données? Si l'ensemble contient plus de 100 enregistrements, vous ne devez pas tous les utiliser, mais utilisez find_in_batches. Il utilise des limites et des décalages pour exécuter votre code par lots et ne pas charger la totalité de la table en mémoire. Vous devez inclure la clé primaire dans la sélection car elle l'utilise pour effectuer l'ordre et la limite. Exemple:

Model.find_in_batches(:batch_size => 100) do |group| 
    group.each {|item| item.do_something_interesting } 
end 
+0

'all' est un alias pour' find (: all) 'qui appelle finalement' find_by_sql' qui est précisément la raison pour laquelle je ne comprends pas le ralentissement . Comme je l'ai dit, je sais que ce n'est pas l'appel le plus efficace, mais si cela ne fonctionne pas, des appels plus efficaces ne fonctionneront pas non plus. Je ne peux pas appeler 'find_in_batches' (ou plus justement,' find_each') à cause de la structure de ma base de données, mais c'est à côté du point. Merci d'avoir répondu. –

2

ScottD est correct. L'appel find_by_sql ne crée pas le ralentissement que vous voyez B_. Les problèmes de vitesse sont dus au fait que Model.all charge une instance de modèle en mémoire pour chaque enregistrement extrait. Cela peut entraîner une défaillance complète avec un ensemble de résultats suffisamment important. Pour info, ceci est très bien couvert dans les guides Rails ici: http://guides.rubyonrails.org/active_record_querying.html#retrieving-multiple-objects