2015-08-22 1 views
0

Dans ma méthode de contrôleur pour la vue d'index j'ai la ligne suivante.Pourquoi la méthode where() exécute-t-elle des requêtes SQL après que toutes les relations imbriquées ont été chargées?

@students_instance = Student.includes(:memo_tests => {:memo_target => :memo_level}) 

Ainsi, pour chaque Student je hâte charge toute l'information nécessaire.

Plus tard dans un bloc .map, j'appelle la méthode .where() sur l'une des relations comme indiqué ci-dessous.

@all_students = @students_instance.map do |student| 

... 

last_pass = student.memo_tests.where(:result => true).last.created_at.utc 
difference_in_weeks = ((last_pass.to_i - current_date.to_i)/1.week).round 

... 

end 

Cela conduit à une seule requête SQL pour chaque student. Et comme j'ai plus de 300 étudiants, cela conduit à des temps de chargement très lents et à plus de 300 requêtes SQL. J'ai raison de penser que cela est dû à la méthode .where(). Je pense que c'est parce que j'ai tout vérifié et ce sont les deux lignes qui causent toutes les requêtes.

Plus important encore, existe-t-il une meilleure façon de faire cela qui réduit ces requêtes à une seule requête?

+0

Vous souhaitez donc recevoir un dernier memo_test pour chaque étudiant? –

+0

Chose est cette requête sera assez compliquée et je ne suis même pas sûr si c'est possible de faire dans ActiveRecord. Peut-être que vous devrez aller quelque chose comme suite ou écrire vous-même sql –

+0

Pas exactement, j'ai déjà accès à «memo_tests» de chaque élève sans lancer une requête. Je veux exécuter la méthode '.where', sans utiliser de requête SQL. – nonsequiter

Répondre

1

Au moment où vous demandez where, la déclaration est traduite en requête. Normalement, le résultat devrait être mis en cache sql ...

Quoi qu'il en soit, pour être sûr, vous pouvez ajouter une logique de programmation à votre déclaration. De cette façon, vous ne demandez pas une instruction NEW.

last_pass = student.memo_tests.map {|m| m.created_at if m.result}.compact.sort.last 

EDIT Je vois la question ne nécessite pas de l'OP de tri ... Donc, en laissant le tri:

last_pass = student.memo_tests.map {|m| m.created_at if m.result}.compact.last 

compact est nécessaire pour éliminer zéro les résultats du tableau.

+0

Cette solution peut être encore plus lente que l'original. –

+0

Comment? S'il y a SQL, il y aura beaucoup ou peu de résultats ... Beaucoup de résultats, SQL lent, tri plus lent ... Peu de résultats, SQL rapide, tri rapide ... Pas de SQL ... plus lent ??? –

+0

Dans la réponse originale, vous avez cartographié compact et trier sur une collection de longueur indéterminée. Il est rarement plus rapide que SQL, et même si les gens de Rails sont impopulaires, une solution SQL pure est le meilleur moyen d'y parvenir. –