2

更新开始

这个问题是为每个项目呈现一个表单,而不是 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 %>
4

3 回答 3

6

项目加载仅需 2.3 毫秒。渲染项目/_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)

最好不要将数据库查询放在您的视图中。尝试通过控制器执行此操作。

于 2012-12-14T13:24:23.833 回答
1

您现在可以使用新发布的 gem 'query_optimizer' 。query_optimizer 是在 rails 中优化 has_many 和 belongs_to 关系两个表的查询的最佳 gem

于 2015-10-21T08:07:19.203 回答
0

由于还没有人提到它,子弹 gem非常适合识别应用程序中的页面,在这些页面中您无意中创建了 N+1 个查询(您的特定情况),这些查询可能受益于急切加载(使用includes已接受的答案中概述的内容)和反缓存

这篇很棒的帖子以简单、清晰的语言概述了问题和解决方案,并介绍了如何使用子弹宝石。还有一个关于实现子弹的RailsCast ,虽然我没有经历过。

于 2016-01-08T22:01:16.740 回答