我有一個「貸款」的模式在Rails中,我試圖建立。有一個相應的「付款」模式。貸款餘額是貸款的原始金額減去所有付款的總和。計算餘額很容易,但我試圖計算大量貸款的餘額,同時避免N + 1查詢,同時使「餘額」成爲「貸款」模型的一個屬性。Rails中,使用自定義的SQL查詢來填充ActiveRecord的模式
當我打電話貸款控制器的索引方法,我可以運行一個自定義選擇查詢,這讓我通過直接的SQL查詢返回一個「平衡」的屬性。
class LoansController < ApplicationController
def index
@loans = Loan
.joins("LEFT JOIN payments on payments.loan_id = loan.id")
.group("loans.id")
.select("loans.*, loans.amount - SUM(payments.amount) as balance")
end
def index_002
@loans = Loan.includes(:payments)
end
def index_003
@loans = Loan.includes(:payments)
end
end
class Loan < ActiveRecord::Base
has_many :payments
def balance=(value)
# I'd like balance to load automatically in the Loan model.
raise NotImplementedError.new("Balance of a loan cannot be set directly.")
end
def balance_002
# No N+1 query, but iterating through each payment in Ruby
# is grossly inefficient as well
amount - payments.map(:amount).inject(0, :+)
end
def balance_003
# Even with the "includes" in the controller, this is N+1
amount - (payments.sum(:amount) || 0)
end
end
現在我的問題是如何隨時使用我的貸款模式做到這一點。通常情況下的ActiveRecord加載一個或使用以下查詢更多型號:
SELECT * FROM loans
--where clause optional
WHERE id IN (?)
有沒有什麼辦法,以便它加載下面的查詢重寫貸款模式:
SELECT
loans.*, loans.amount - SUM(payments.amount) as balance
FROM
loans
LEFT JOIN
payments ON payments.loan_id = loans.id
GROUP BY
loans.id
這樣的「平衡」是一個模型的屬性,只需要在一個地方聲明,但我們也避免了N + 1查詢的低效率。
這種方法的問題是大多數數據庫視圖不能被索引。這意味着要查找記錄,您必須對視圖執行線性掃描。我相信Microsoft SQL Server允許索引視圖。據我所知,Postgres沒有。 –
@SteveZelaznik,這不完全正確。除非物化,否則不能在視圖上創建索引,但是,postgres應該在普通視圖中使用底層表上的索引。 – spike