2012-12-14 103 views
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作为数据库

添加由吉里·波斯皮西尔要求解释运行此。在控制台中,它看起来并不慢。这个解释是在开发中完成的。有同样的问题还有

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

你能解释一下运行查询吗? –

+0

我已经用解释 –

+2

更新了这个问题。项目负载只需要2.3ms。呈现项目/ _index的时间是1秒。查询不是你的瓶颈。或者,也许我错了......我整晚都在睡觉。 –

回答

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同意。 :包含会更快,并且不会在视图中初始化数据库请求。 ActionView - 是整个Rails的一大瓶颈。恕我直言。 –

+1

+1同意使用包括我可以。原来查询是确定的。这是一个渲染问题。我已更新问题。元;我应该回答自己的问题并接受它吗?根据我的问题,没有人能够回答这个问题。这是一个非常好的答案,即使它没有解决问题 –

+0

你大概可以回答你自己的问题。我简单地看了一下这个视图,乍一看没有什么突出的。 –

1

您现在可以使用新发布的gem 'query_optimizer' 。 query_optimizer是在轨道为的has_many和belongs_to的关系,优化查询两个表

+1

虽然这个链接可能回答这个问题,但最好在这里包含答案的重要部分,并提供供参考的链接。如果链接页面更改,则仅链接答案可能会失效。 – Drenmi

+0

是的,链接是相关的问题用户可以在单个查询中获得所有项目及其成员资格为QueryOptimizer.optimize_query(Project,Membership) – ajooba

+0

更精确QueryOptimizer.optimize_query(Project,Membership).select {| user | user [“users_id”] ==“#{current_user.id}”} – ajooba

0

由于还没有人提到它的最好的宝石,在bullet gem是优秀的在你的应用程序,你在不经意间创造了N + 1个查询识别页面(您的具体情况),可能受益于渴望加载(使用includes如在接受的答案中概述)和反高速缓存

这个伟大的post概述了简单,清晰的语言的问题和解决方案,并介绍了使用子弹宝石。在执行bullet时也有RailsCast,虽然我还没有经过它。