2012-12-14 152 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,雖然我還沒有經過它。