dans mon action de contrôleur, i i'v a découvert que la vue communique toujours avec la base de données (17 requêtes):
p>
blockQuote> ces voici le Query dans mon contrôleur, cela empêche d'éviter le inclus code> Toutes les associations nécessaires à la vue, pour éviter plusieurs appels à la base de données. (J'essaie d'isoler la couche de vue pour rendre les données collectées par le contrôleur).
17 requêtes supplémentaires code> strong> ne sont pas nécessaires. Étant donné que j'ai testé les requêtes du contrôleur de la console et collectionne avec succès toutes les données nécessaires à la partielle
_dropdown code> (dans 5 requêtes forte>) sans aucune nouvelle communication de base de données. p>
N + 1 code> problème. (Y compris toutes les variables appelées dans la vue) p>
voici le code déroulant: h3>
sortie de la console: H3>
2.0.0-p353 :006 > ms = Message.dropdown_for(3).all
Message Load (1.2ms) SELECT "messages".* FROM "messages" LEFT JOIN messages AS m ON messages.id != m.id
AND m.conversation_id = messages.conversation_id
AND messages.created_at < m.created_at INNER JOIN conversation_participants AS cp ON cp.conversation_id = messages.conversation_id AND cp.user_id = 3 WHERE (m.id IS NULL) ORDER BY cp.seen , cp.updated_at DESC LIMIT 5
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (6, 4, 5)
Conversation Load (0.4ms) SELECT "conversations".* FROM "conversations" WHERE "conversations"."id" IN (4, 2, 3)
ConversationParticipant Load (0.2ms) SELECT "conversation_participants".* FROM "conversation_participants" WHERE "conversation_participants"."conversation_id" IN (4, 2, 3)
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" IN (6, 3, 4, 5)
=> [#<Message id: 8, body: "saSasa", sender_id: 6, conversation_id: 4, sent: true, attachment_id: nil, attachment_type: nil, created_at: "2014-11-17 16:05:40", updated_at: "2014-11-17 16:05:40">, #<Message id: 2, body: "asdnas dagsdashjdg jahs d", sender_id: 4, conversation_id: 2, sent: true, attachment_id: nil, attachment_type: nil, created_at: "2014-11-17 11:32:36", updated_at: "2014-11-17 11:32:36">, #<Message id: 6, body: "SADASD A DSA ", sender_id: 5, conversation_id: 3, sent: true, attachment_id: nil, attachment_type: nil, created_at: "2014-11-17 13:43:34", updated_at: "2014-11-17 13:43:34">]
2.0.0-p353 :007 > ms.first.conversation.conversation_participants.select{|cp| cp.user_id != 3}.first.user
=> #<User id: 6, first_name: "Ddsfsd", middle_name: nil, last_name: "Fsdfsd", photo: nil, email: "1@k.com", encrypted_password: "$2a$10$5sGIb2DbQ1ctMrTzD3AJ0uV18hhiC5Ei1wcfE7MSAvRU...", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 1, current_sign_in_at: "2014-11-17 15:27:06", last_sign_in_at: "2014-11-17 15:27:06", current_sign_in_ip: "127.0.0.1", last_sign_in_ip: "127.0.0.1", confirmation_token: nil, confirmed_at: "2014-11-17 15:27:48", confirmation_sent_at: "2014-11-17 15:27:05", unconfirmed_email: nil, failed_attempts: 0, unlock_token: nil, locked_at: nil, authentication_token: nil, created_at: "2014-11-17 15:27:05", updated_at: "2014-11-17 15:27:48", slug: "ddsfsd_fsdfsd">
2.0.0-p353 :008 > ms.count
=> 3
6 Réponses :
Cela peut être appelé "N + 1", cela se produit en raison de la chargement paresseux. Je ne peux pas dire avec certitude sans journal d'application. Vous pouvez utiliser le chargement impatient comme décrit ici . P>
J'utilise déjà précharge code> et
eager_load code> pour collecter mes données dans le contrôleur.
Vous pouvez essayer BUNLET GEM qui vous dira qu'il y a une prolème N + 1 dans la requête. S'il n'y a pas de problème de problème N + 1, vous devriez essayer d'implémenter la mise en cache de fragments. P>
Comment cela pourrait-il se produire que du serveur (dans la console tout va bien)?
Essayez les rails-footnotes GEM qui afficheront toutes les requêtes de vues comme contrôleur de la ligne avec des numéros de ligne. Github.com/josevalim/rails-footNotes
Question simple. Avez-vous essayé de mettre un. to_a code> à la fin de votre méthode appelez?
Comme
@ messages.a_a code>? P>
Ceci est vraiment embrassant que je n'ai pas essayé to_a code>. Maintenant, le
17 code> déplacé sur le contrôleur et le
5 code> a disparu, si je pensais à éliminer les inutiles, je vais vous donner la prime. Merci pour l'indice.
Heureux de pouvoir vous aider, à la fin! Faites le nous savoir!
Je vérifierais le journal pour voir ce que ces 17 questions sont, ou peut-être en cliquant sur le lien EDIT: P>
Comme indiqué dans la section "Chargement paresseux" de Ce site , vous Peut ajouter 17 SQL CODE> affichera ces questions. À partir de là, vous pourrez peut-être voir que vous avez oublié de
inclut code> une table qui provoque le problème N + 1. p>
.all code> à la fin de votre requête dans votre action de contrôleur pour déclencher son exécution et empêcher la requête d'exécuter de manière paresseuse à votre vue. Comme mentionné dans mon commentaire, Rails Slopes vous permet de construire des requêtes et d'exécuter lorsque vous les utilisez. Pour exécuter, vous pouvez appeler .Toutez. Dans les rails 4, vous pouvez utiliser
.charger code >
pour exécuter la requête dans le contrôleur. P>
Dans Rails 4+, .Alle code> construira un objet code> objet code> et ne déclenche pas la requête instantanément. Au lieu de cela, vous devrez appeler
to_a code> sur votre requête.
TRUE, Toutefois, pour les rails 4, j'utiliserais all.load code> pour renvoyer une action activeecordrelation sur
to_a code>.
Génial, ne le savait pas. Merci!
Votre requête n'est pas bien formulée. Vous devez soit utiliser Inclus ou des jointures.
Casser votre requête en deux comme suit: P>
message_ids = Message.joins("LEFT JOIN messages AS m ON messages.id != m.id AND m.conversation_id = messages.conversation_id AND messages.created_at < m.created_at") .where('m.id IS NULL') .joins("INNER JOIN conversation_participants AS cp ON cp.conversation_id = messages.conversation_id AND cp.user_id = #{user_id}") .order("cp.seen, cp.updated_at DESC") .limit(5).map(&:id) messages = Message.includes(:sender). includes(conversation: [{conversation_participants: :user}]). where(id: message_ids)
Eh bien, je respecte votre approche, mais cela ajoute une autre requête. Je ne peux pas comprendre exactement quelle est la différence entre la console et le serveur.
Je n'ai rien dit sur la console et le serveur. Fondamentalement, il n'est pas possible d'utiliser des jointures avec une limite d'Activerecords. Ce que je vous ai fourni est la solution la meilleure et la plus correcte. Vous avez juste une requête supplémentaire au lieu des 17 que vous avez à l'origine et c'est ainsi que vous développez ces solutions.
Eh bien, votre approche les a faite 18. Et ce n'est pas une limitation si vous regardez la sortie de la console.
Bien après avoir débogué tous les facteurs possibles pouvant causer ce problème.
J'ai essayé de définir J'ai conclu que (par défaut), le schéma n'est pas chargé pour aucun modèle lorsque les classes ne sont pas cachées. En d'autres termes, lorsque Voici un problème similaire Méthode de colonne_DeFinitions appelée avant et après chaque instruction SQL sur PostgreSQL . p>
config.cache_classes code> sur true, dans mon
développement.rb code>. Cela a supprimé avec succès toutes les requêtes supplémentaires. P>
config.cache_classes code> est défini sur
false code>, le schéma de chaque modèle est chargé pour chaque demande de requête distincte. P>
* Conclusion h3>
cache_classes code> doit être défini sur
false code> dans
développement code> environnement.
Ignorer les requêtes internes supplémentaires de l'adaptateur de connexion PostgreSQL
chargement du schéma pour chaque modèle car il ne va pas affecter votre
Environnement de production (production a
config.cache_classes code> défini sur
vrai code>). p>
blockQuote>
Config.Cache_clases n'a rien à voir avec les requêtes. Ce que j'ai fourni est la solution correcte et ne doit pas causer de 18 ans.
@Arkhitech Votre solution n'est rien d'autre qu'une requête supplémentaire. Je l'ai testé bien que je sache sa mauvaise solution. J'utilise PostgreSQL, à la caisse du problème similaire.
hmmm ... Je n'ai pas la configuration de l'environnement pour tester manuellement cela, mais config.cache_classes ne peut aucun effet sur les requêtes.
Chargement du schéma de classe (modèle) apparaît comme une requête en mini-profileur
Le problème a été signalé au mini-profileur ici: link1 et link2
En fait, j'ai essayé de déconnecter de la console, tout fonctionne comme prévu, mais je reçois une erreur lorsque je l'ajoute dans mon contrôleur (accéder aux mêmes attributs) du serveur.
Pourriez-vous s'il vous plaît poster le code pour vos fichiers d'index et d'affichage déroulant et l'action de conversation du contrôleur?
Les Slopes Rails vous permettent de créer des requêtes et d'exécuter lorsque vous les utilisez. Pour exécuter, vous pouvez appeler .Toutez. Avez-vous essayé d'ajouter
.all code> à la fin de votre requête dans l'action du contrôleur?
Oui, je l'ai fait, aussi
to_a code>. La chose est la précharge semble prendre plus de questions que cela devrait.
Depuis le journal, pourriez-vous coller les 17 requêtes que vous souhaitez éliminer / ne pensez-vous pas qu'ils sont nécessaires? Vous pouvez simplement coller une des questions s'ils sont tous à peu près les mêmes.
J'ai posté la même requête de la console, indiquant aucune communication de base de données supplémentaire lors de l'appel des associations.
Je m'attendais à ces 5 déclarations sélectionnées, mais ne voyez pas les 17 requêtes supplémentaires. Avez-vous des filtres (avant / après) qui relient-vous à votre action de contrôleur ou à tout autre code dans votre action de contrôleur?
Ces requêtes générées disparaissent lorsque je commente la ligne
@Messages code>. Je commence à penser que c'est un problème avec le profileur ou la version de mes rails.
Au lieu de comparer
message.sender code> à
actuel_user code>, comparer
message.sender_id == actuel_user.id code>: une requête moins par message? :) Aussi: stockez le résultat dans une variable et effectuez le test qu'une seule fois.
L'expéditeur est déjà préchargé, car j'ai besoin de l'expéditeur
code>
Merci à tout le monde, j'ai enfin trouvé la solution à mon problème. J'apprécie vraiment votre effort.