如何获取关联模型的最后一条记录以防止 N+1 查询?

How to fetch an associated model's last record to prevent N+1 queries?

我有一个模型 Invoice has_many Payments 和一个模型 Payment belongs_to Invoice.

我们每月批量导出发票数据,需要每张发票的最后一笔付款。

在我们看来,我们目前正在为每个要导出的发票执行一次 Invoice.payments.last,我被要求防止 N+1 次查询。

我不明白是否应该在控制器或发票模型中添加此查询,或者它是否应该是 has_one :last_payment 关联或范围。

如有任何帮助,我们将不胜感激。

如果每张发票的付款次数相对较少,您可以 include/eager_load/preload 协会:

invoices = Invoice.includes(:payments)
invoices.each do |i|
  puts i.payments.last.amount # no n+1 query
end

然而,这会立即将所有相关记录加载到内存中。这可能会导致性能问题。

一个非常高效的读取优化是将外键列添加到发票 table 和一个 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

成本是每条插入记录的额外更新查询。可以使用 DB 触发器而不是 association callback.

对其进行优化