簡體   English   中英

在rails SQL查詢上優化ruby

[英]Optimize ruby on rails SQL queries

更新開始

問題在於為每個項目呈現一個表單,而不是為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 %>

項目負載僅需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)

最好不要在視圖中放入數據庫查詢。 嘗試通過控制器執行此操作。

您現在可以使用新發布的gem'query_optimizer' query_optimizer是在has_many和belongs_to關系兩個表中優化Rails中查詢的最佳工具

由於還沒有人提及它, 子彈寶石非常適合識別您的應用程序中的頁面,在這些頁面中您無意中創建了可能受益於預先加載的 N + 1查詢(您的特定情況)(使用includes在接受的答案中已詳細說明)和反緩存

這篇出色的文章以簡單,清晰的語言概述了問題和解決方案,並簡要介紹了使用bullet gem。 雖然我沒有通過它,但還有一個關於實施子彈RailsCast

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM