我正在尝试在具有很多n + 1个查询的Rails应用程序上加快索引页面的速度。
目前,我有一种基本上可以反转关系的方法(查找与当前记录不相关的记录)
Class Person < ActiveRecord::Base
has_many_and_belongs_to_many :bankholidays, join_table: “working_bankholidays”
def free_bankholidays
Bankholiday.where(“id NOT IN (?)” bankholiday_ids)
end
end
Class Bankholiday < ActiveRecord::Base
has_many_and_belongs_to_many :persons, join_table: “working_bankholidays”
end
Class WorkingBankholiday < ActiveRecord::Base
belongs_to :person
belongs_to :bankholiday
end
Person内部的free_bankholidays方法返回与当前Person无关的任何Bankholiday。这可以正常工作,但是如果我要由多个人加载索引页,则速度会变慢。有什么方法可以将其移至恋爱关系中,从而使其渴望加载?
答案 0 :(得分:0)
您需要的是向外联接,然后选择外部联接创建NULL的结果。
您想要的SQL是:
SELECT bankholidays.*
FROM bankholidays
LEFT OUTER JOIN working_bankholidays on bankholidays.id = working_bankholidays.bankholiday_id
AND working_bankholidays.person_id = 111
WHERE working_bankholidays.id is NULL
这里的问题是,您需要 person_id
子句中FROM
的条件。如果在WHERE
子句中,您将得到不同的结果。
当它位于FROM子句中时,它将使用条件处理working_bankholidays
表,就好像它只有具有匹配的person_id
的行一样。这样做是在进行外部联接之前进行的,因此,如果没有匹配person_id
的记录,它将添加来自外部联接的记录,并且working_bankholidays
表的所有字段中的值均为NULL。>
不幸的是,对于活动记录关联,我不知道有什么方法可以做到这一点。所有活动记录关联都将条件置于WHERE
子句中,而不是FROM
子句中。
如果将has_many_and_belongs_to_many
更改为具有很多贯穿,则可以执行以下操作:
class Person
def free_bankholidays
Bankholiday.left_joins(:working_bankholidays).where(working_bankholidays: {id: nil, person_id: self.id})
end
它将为您提供:
SELECT bankholidays.*
FROM bankholidays
JOIN working_bankholidays on bankholidays.id = working_bankholidays.bankholiday_id
WHERE working_bankholidays.id is NULL
AND working_bankholidays.person_id = 111
这将为您带来不同且错误的结果。
编辑:
请参阅Engineersmnky的评论。我还没有尝试过,所以还没有准备好将其包含在答案中。