¿Cómo reducir (masivamente) el número de consultas SQL en la aplicación Rails?
En mi aplicación Rails tengousers
que puede tener muchosinvoices
el cual a su vez puede tener muchospayments
.
Ahora en eldashboard
Ver Quiero resumir todo elpayments
a user
ha recibido, ordenado por año, trimestre o mes. lospayments
también se subdividen enbruto, redyimpuesto.
usuario.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
factura.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
pago.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) %>
Ahora el problema es que este enfoque funciona, pero también produce una gran cantidad de consultas SQL. En un tipicodashboard
vista obtengo100+ Consultas SQL Antes de añadir.includes(:invoice)
Hubo aún más consultas.
Supongo que uno de los principales problemas es que cada facturasubtotal
, total_tax
ytotal
no se almacenan en ninguna parte de la base de datos, sino que se calculan con cada solicitud.
¿Alguien puede decirme cómo acelerar las cosas aquí? No estoy muy familiarizado con SQL y el funcionamiento interno de ActiveRecord, por lo que probablemente ese sea el problema aquí.
Gracias por cualquier ayuda.