Как (массово) уменьшить количество SQL-запросов в приложении Rails?

В моем приложении Rails у меня естьusers которые могут иметь многоinvoices которые в свою очередь могут иметь многоpayments.

Сейчас вdashboard посмотреть я хочу обобщить всеpayments a user когда-либо получил, заказал либо по году, кварталу или месяцу.payments также подразделяются наваловой, сеть, а такженалог.

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

invoice.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) %>

Теперь проблема в том, что этот подход работает, но также генерирует очень много SQL-запросов. В типичномdashboard посмотреть я получаю100+ SQL-запросы. Перед добавлением.includes(:invoice) было еще больше запросов.

Я предполагаю, что одной из основных проблем является то, что каждый счетsubtotal, total_tax а такжеtotal нигде не хранятся в базе данных, а рассчитываются с каждым запросом.

Кто-нибудь может сказать мне, как ускорить процесс здесь? Я не слишком знаком с SQL и внутренними принципами работы ActiveRecord, так что, вероятно, проблема здесь.

Спасибо за любую помощь.

Ответы на вопрос(3)

Ваш ответ на вопрос