Jak (masowo) zmniejszyć liczbę zapytań SQL w aplikacji Rails?

W mojej aplikacji Rails mamusers które mogą mieć wieleinvoices które z kolei mogą mieć wielepayments.

Teraz wdashboard widok Chcę podsumować wszystkiepayments a user kiedykolwiek otrzymał, uporządkowany według roku, kwartału lub miesiąca. Thepayments są również podzielone naobrzydliwy, netto, ipodatek.

user.rb:

class User < ActiveRecord::Base

  has_many  :invoices
  has_many  :payments

  def years
    (first_year..current_year).to_a.reverse
  end

  def year_ranges
    years.map { |y| Date.new(y,1,1)..Date.new(y,-1,-1) }
  end

  def quarter_ranges
    ...
  end

  def month_ranges
    ...
  end

  def revenue_between(range, kind)
    payments_with_invoice ||= payments.includes(:invoice => :items).all
    payments_with_invoice.select { |x| range.cover? x.date }.sum(&:"#{kind}_amount") 
  end

end

faktura.rb:

class Invoice < ActiveRecord::Base

  belongs_to :user
  has_many :items
  has_many :payments

  def total
    items.sum(&:total)
  end

  def subtotal
    items.sum(&:subtotal)
  end

  def total_tax
    items.sum(&:total_tax)
  end

end

payment.rb:

class Payment < ActiveRecord::Base

  belongs_to :user
  belongs_to :invoice  

  def percent_of_invoice_total
    (100 / (invoice.total / amount.to_d)).abs.round(2)
  end

  def net_amount
    invoice.subtotal * percent_of_invoice_total / 100
  end  

  def taxable_amount
    invoice.total_tax * percent_of_invoice_total / 100
  end

  def gross_amount
    invoice.total * percent_of_invoice_total / 100
  end

end

dashboards_controller:

class DashboardsController < ApplicationController

  def index    
    if %w[year quarter month].include?(params[:by])   
      range = params[:by]
    else
      range = "year"
    end
    @ranges = @user.send("#{range}_ranges")
  end

end

index.html.erb:

<% @ranges.each do |range| %>

  <%= render :partial => 'range', :object => range %>

<% end %>

_range.html.erb:

<%= @user.revenue_between(range, :gross) %>
<%= @user.revenue_between(range, :taxable) %>
<%= @user.revenue_between(range, :net) %>

Teraz problem polega na tym, że to podejście działa, ale generuje również wiele zapytań SQL. W typowymdashboard widok dostaję100+ Zapytania SQL. Przed dodaniem.includes(:invoice) było jeszcze więcej pytań.

Zakładam, że jednym z głównych problemów jest fakturasubtotal, total_tax itotal nie są przechowywane w żadnym miejscu w bazie danych, ale zamiast tego są obliczane przy każdym żądaniu.

Czy ktoś może mi powiedzieć, jak przyspieszyć tutaj? Nie jestem zbyt zaznajomiony z SQL i wewnętrznym działaniem ActiveRecord, więc to prawdopodobnie problem tutaj.

Dzięki za pomoc.

questionAnswers(3)

yourAnswerToTheQuestion