如果每张发票的付款次数相对较少,您可以只包含/eager_load/preload 关联:
invoices = Invoice.includes(:payments)
invoices.each do |i|
puts i.payments.last.amount # no n+1 query
end
但是,这会将所有关联的记录一次加载到内存中。这可能会导致性能问题。
一个非常高效的读取优化是将外键列添加到发票表和一个belongs_to关联,您可以在急切加载时使用它:
class AddLatestPaymentToInvoices < ActiveRecord::Migration[6.0]
def change
add_reference :invoices, :latest_payment, null: false, foreign_key: { to_table: :payments }
end
end
class Invoice < ApplicationRecord
has_many :payments, after_add: :set_latest_invoice!
belongs_to :latest_payment,
class_name: 'Payment'
private
def set_latest_payment(payment)
update_columns(latest_payment_id: payment.id)
end
end
invoices = Invoice.includes(:latest_payment)
invoices.each do |i|
puts i.latest_payment.amount # no n+1 query
end
成本是插入的每条记录的额外 UPDATE 查询。它可以通过使用 DB 触发器而不是 association callback 来优化。