2017-05-25 100 views
0

在我的Rails應用程序中,我有一個引用其他幾個對象的TimeEntry模型。下面是遷移:如何加快此查詢/頁面?

class CreateTimeEntries < ActiveRecord::Migration[5.0] 
    def change 
    create_table :time_entries do |t| 
     t.references :user, foreign_key: true 
     t.references :customer, foreign_key: true 
     t.references :site, foreign_key: true 
     t.date :work_date 
     t.integer :hours 
     t.integer :minutes 
     t.references :service, foreign_key: true 
     t.references :task, foreign_key: true 

     t.timestamps 
    end 
    end 
end 

我已經把需要從UserSiteTask關聯領域的報告,使用此代碼:

@time_entries = TimeEntry.joins(:customer, :site) 
.where('time_entries.work_date >= ? AND time_entries.work_date <= ?', @start_date, @end_date) 
.where(customer: @customer) 

注:@customer在加載before_action,可以是單個客戶,也可以是所有300+客戶

在我看來,客戶在按名稱控制器一起:

@time_entry_customers = @time_entries.group_by { |time| time.customer.name } 

性能如下: Completed 200 OK in 12308ms (Views: 8508.7ms | ActiveRecord: 924.5ms)

因此,查詢的不是速度極快,但視圖是真正的問題。我做更多的分組視圖,通過客戶的網站:

<% @time_entry_customers.each do |customer, time| %> 
    <tr class="success"> 
    <td colspan="6"> 
     <strong><i class="fa fa-user"></i> <%= customer %></strong> 
    </td> 
    </tr> 

    <% time.group_by { |t| t.site.url }.each do |site, time_entries| %> 
    <tr> 
     <td></td> 
     <td class="site-row" colspan="5"><i class="fa fa-globe"></i> <%= site %></td> 
    </tr> 

     <% time_entries.each do |time_entry| %> 
     <tr> 
     <td colspan="2"></td> 
     <td><%= time_entry.work_date %></td> 
     <td><%= time_entry.try(:user).try(:full_name) %></td> 
     <td><%= time_entry.task.name %></td> 
     <td><%= time_entry.hours %> : <%= time_entry.minutes %></td> 
     </tr> 
     <% end %> 

    <tr> 
    <td></td> 
    <td class="info" colspan="4"><i class="fa fa-clock-o"></i> Total Time for <%= site %></td> 
    <td class="info"><%= sum_time_entries_as_hours_and_minutes(time_entries) %></td> 
    </tr> 
    <% end %> 

<% end %> 

控制器和視圖之間,這最終被成千上萬的查詢(有〜47000 TimeEntries和〜400 Customers

如何我可以重構這個表現嗎?

users.email以外,沒有任何數據庫表具有任何索引。

回答

0

根據本頁的用例和性能預期,有幾種解決此問題的方法。

選項1:由於您提到有47k行顯示在頁面中,用戶可能不需要一次查看所有數據。因此,您可以首先顯示高級別摘要(每個客戶和時間在網站上花費的總時間),然後爲每個網站和客戶行提供選項以進一步擴展以顯示各個時間條目。要以最有效的方式執行此操作,可以使用group方法ActiveRecordpluck中的customer_id,customer_name,site_id,site_name,花費的總時間在DB級別執行分組。

http://guides.rubyonrails.org/active_record_querying.html#group http://guides.rubyonrails.org/active_record_querying.html#pluck

選項2:考慮到一次顯示所有的47K記錄是必須的,最好是查詢只顯示而不是加載整個對象層次列。與加載所有對象相比,這會表現得更好。以下代碼未經過測試,但它提供了一個想法。

TimeEntry.joins(:customer, :site, :user, :task)..where('time_entries.work_date >= ? AND time_entries.work_date <= ?', @start_date, @end_date).pluck('time_entries.work_date,users.full_name,time_entries.hours,time_entries.minutes,tasks.name, customers.id, customers.name,sites.id, sites.url').order('customers.id,sites.id') 

上述查詢將返回所有47k行的數組。您既可以在customers.id和sites.id上執行group_by,也可以通過客戶和站點進行排序,您可以循環遍歷所有行,並且每當遇到與前一行相比客戶或站點發生更改時,都可以顯示這些行頭。