Additional Requests Listed in MiniProfiler

In my controller action, I included all the associations necessary for the submission to avoid multiple calls in the database. (I am trying to isolate the views layer to display only the data collected by the controller).


I found out that the view is still communicating with the database (17 queries): Miniprofiler


These 17 extra queries not needed. Since I checked controller requests from the console and successfully collected all the data needed by partial _dropdown (in 5 requests ) without further communication with the database.

Here is the request in my controller, it wants to avoid the N+1 problem. (Including all variables called in the view)


Here is the dropdown code:

 - @messages.each do |message| %li.conversation-container %a{href: conversation_path(message.conversation_id)} - if message.sender != current_user .notification-avatar{style: "background: url(#{message.sender.avatar_url}); background-size: contain; background-repeat: no-repeat; background-position: 50% 50%;"} - else - other_participant = message.conversation.conversation_participants.select{|p| p.user_id != current_user.id }.first.user .notification-avatar{style: "background: url(#{other_participant.avatar_url}); background-size: contain; background-repeat: no-repeat; background-position: 50% 50%;"} %p %strong - if message.sender != current_user = message.sender.name - else = other_participant.name %br - if message.sender == current_user %i.fa.fa-mail-reply-all = truncate(message.body,length: 25) .time = time_ago_in_words(message.created_at) ago - if @messages.count == 0 %li .empty-state-text-white No messages 

Console Output:

 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 

How can I stop the execution of these requests without any purpose?

+7
performance ruby-on-rails ruby-on-rails-3 eager-loading preloading
source share
6 answers

* Debugging

Good after debugging all the possible factors that might cause this problem. I tried setting config.cache_classes to true in my development.rb . This has successfully removed all additional requests.

I came to the conclusion that (by default) the scheme does not load for any model when classes are not cached. In other words, if config.cache_classes set to false , the schema for each model is loaded for each request as a separate request.

Here is a similar column_definitions method , which is called before and after each individual PostgreSQL SQL statement .

* Conclusion

cache_classes should be set to false in the development environment. Ignore additional internal requests from the postgresql connection adapter loading the schema for each model, since it will not affect your model production environment (production config.cache_classes set to true ).

+6
source share

You can try the bullet marker, which will tell you if the request has N + 1 problems. If there are no problems with N + 1, then you should try to implement fragment caching.

+3
source share

Simple question. Have you tried putting a. to_a at the end of a method call? How is @messages.to_a ?

+2
source share

I would check the log to see what these 17 queries are, or perhaps clicking on the 17 sql link will show these queries. From there, you can see that you forgot to includes table that causes the N + 1 problem.

EDIT:

As noted in the Lazy Loading section of this site , you can add .all to the end of your request in your controller to initiate its execution and prevent lazy execution of the request in your view. As mentioned in my comment, Rails areas allow you to create queries and execute them when you use them. You can call .all, .count, .each or .first for execution. In Rails 4, you can use .load to execute a request in a controller.

+2
source share

This may be the so-called "N + 1" problem, this is due to lazy loading. I can not say for sure without the application log. You can use active download as described here .

+1
source share

Your request is poorly worded. You must either enable or join.

Divide the query into two as follows:

 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) 
+1
source share

All Articles