ruby-on-rails - 我可以根据没有匹配项创建 Active Record 关系吗
问题描述
我正在尝试加快具有大量 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 无关的任何 Bankholidays。如果我正在加载包含多人的索引页面,这可以正常工作,但会减慢速度。有没有办法可以将其转移到关系中,以便可以急切地加载?
解决方案
您需要的是一个外连接,并选择外连接创建 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
inFROM
子句的条件。如果它在WHERE
子句中,您将得到不同的结果。
当它在 FROM 子句中时,它将使用条件将working_bankholidays
表视为只有匹配的行person_id
。它在执行外连接之前执行此操作,因此如果没有匹配的记录,person_id
它将添加来自外连接的记录,working_bankholidays
表的所有字段中的值为 NULL。
不幸的是,我不知道有什么方法可以通过活动记录关联来做到这一点。所有活动记录关联都将条件放入WHERE
子句,而不是FROM
子句。
如果你改变has_many_and_belongs_to_many
to 有很多通过,你这样做:
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 的评论。我还没有尝试过,所以我还没有准备好将它包含在我的答案中。
推荐阅读
- java - 应该计算数组中所有对的代码不能正确工作
- google-cloud-firestore - 如何使用 Google 登录访问 Actions on Google 中受保护的数据库?
- node.js - 是否可以在不重新启动服务器的情况下更新 ssl 证书?
- c# - 当 WCF 托管在 IIS 中时,是否有必要关闭 WCF 调用的连接
- c# - XPS 到 PDF 转换
- php - 将对象转换为数组导致 foreach 循环中的错误空响应
- regex - 执行非常大的正则表达式操作的最佳方法是什么?
- c++ - 有没有办法让用户输入在 Visual Studio 中定义数组大小?
- python - 如何在绘图交互式绘图中手动更改标记形状
- python - 向 SQL 查询传递多个参数时 Python 崩溃