更新开始
此问题是为每个项目呈现表单,而不是使用SQl查询。为了优化,我将根据需要使用javascript添加表单。
好像我没有看到miniprofiler日志正确。我道歉,但留下可能有类似问题的其他人的问题。
更新结束
我正在使用miniprofiler在我的应用中找到瓶颈。我找到了一个!
SELECT "projects".* FROM "projects" INNER JOIN "memberships" ON
"projects"."id" = "memberships"."project_id" WHERE
"memberships"."user_id" = 1 AND (active = 't')
1059.50 ms
Rendering: projects/_index — 1023.18 ms
它在1秒内找到了185个项目。
如何进行更高效的查询?
我在我的projects_controller索引
中有这个@projects = current_user.projects.is_active
项目模型中的is_active范围
scope :is_active, where(["active = ?", true])
项目和用户有多对多关系,有会员加入表
会员资格模式
class Membership < ActiveRecord::Base
attr_accessible :project_id,:user_id,:created_at,:updated_at
belongs_to :user
belongs_to :project
end
会员资格表
def self.up
create_table :memberships do |t|
t.integer :project_id
t.integer :user_id
t.timestamps
end
add_index :memberships, [:project_id, :user_id], :unique => true
end
我在本地计算机上的生产环境中使用postgreSQL作为数据库
运行它添加JiříPospíšil要求的解释。在控制台中,它似乎并不慢。这个解释是在开发中完成的。那里有同样的问题
User.first.projects.is_active.explain
User Load (0.3ms) SELECT "users".* FROM "users" LIMIT 1
Project Load (2.3ms) SELECT "projects".* FROM "projects" INNER JOIN "memberships" ON "projects"."id" = "memberships"."project_id" WHERE "memberships"."user_id" = 1 AND (active = 't')
EXPLAIN (0.2ms) EXPLAIN QUERY PLAN SELECT "projects".* FROM "projects" INNER JOIN "memberships" ON "projects"."id" = "memberships"."project_id" WHERE "memberships"."user_id" = 1 AND (active = 't')
=> "EXPLAIN for: SELECT \"projects\".* FROM \"projects\" INNER JOIN \"memberships\" ON \"projects\".\"id\" = \"memberships\".\"project_id\" WHERE \"memberships\".\"user_id\" = 1 AND (active = 't')\n0|0|1|SEARCH TABLE memberships USING INDEX index_memberships_on_user_id (user_id=?) (~10 rows)\n0|1|0|SEARCH TABLE projects USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)\n"
视图
<% @projects.each do |project| %>
<li class="tab_list" id="project_<%= project.id.to_s %>">
<div class="tab_list_text"><%= link_to project.name, project_path(project) %></div>
<span class='open_project_update button edit' id="project_update" data-id="<%= project.id %>" data-object="project" title="Edit project">Edit</span>
<div class="dialog_form" id="project_update_<%= project.id %>_form" title="Update project" style="display:none;">
<%= form_for(project) do |f| %>
<ul>
<li><%= f.label :name %><%= f.text_field :name %></li>
<li><%= f.label :description %><%= f.text_field :description %></li>
<li><%= f.label :due %><%= f.text_field :due, :value => project.due.strftime("%Y-%m-%d"), :id => "date_project_#{project.id}" %></li>
<li><%= f.label :customer_id %><%= f.select(:customer_id, @customers.map {|customer| [customer.name, customer.id]}, {:include_blank => 'None'})%></li>
<li><%= f.submit 'Save', :class => 'submit' %></li></ul>
<% end %>
</div>
<a class="activate_project button" data-object="project" data-id="<%= project.id.to_s %>">Archive</a>
</li>
<% end %>
答案 0 :(得分:6)
项目负载仅需2.3ms。渲染项目/ _index的时间是1秒。查询不是您的瓶颈。
根据您的评论,您说您懒得加载关系。确保使用includes
急切加载关系。
例如:
@user.projects.is_active.includes(:some_association).includes(:another_association)
includes
会导致关系被急切加载。
如果您正在迭代用户列表,要获得活动项目,您需要执行以下操作:
User.includes(:projects)
.merge(Project.is_active)
.includes(projects: :some_other_association)
最好不要在视图中放置数据库查询。尝试通过控制器执行此操作。
答案 1 :(得分:1)
您可以使用新发布的gem 'query_optimizer' 现在 query_optimizer是用于优化has_many和belongs_to关系两个表的rails中查询的最佳宝石
答案 2 :(得分:0)
由于还没有人提及, bullet gem 非常适合识别应用中您无意中创建N + 1查询(您的具体案例)的页面,这些查询可能会受益于< strong>急切加载(使用includes
并在接受的答案中概述)和反缓存。
这个伟大的post用简单明了的语言概述了问题和解决方案,并介绍了如何使用bullet gem。实施项目符号还有一个RailsCast,但我没有通过它。