【发布时间】:2015-03-26 08:27:59
【问题描述】:
我正在查询一堆由人们撰写和接收的信件。我通过连接表将字母表与人员表相关联,该连接表使用人员类型标识符(0 = 创建者,1 = 收件人)确定该人是相关信件的创建者还是收件人。
我的问题:我在用户视图中一次显示 50 封信,其中包含日期、创建者、收件人和博物馆收藏等信息。页面加载速度非常慢,因为尽管我已经想出了如何“包含”集合,以便不对正在显示的每个字母运行查询,但我无法为创建者和收件人执行此操作。如果我只是简单地显示“人”,我也可以做一个包含,但由于我按他们的角色过滤他们,rails 对视图中的每个字母运行几个查询,这大约需要 6000 毫秒。如果没有创建者和接收者,视图会在大约 250 毫秒内加载。
以下是我的模型的基础知识:
class ArchiveObject < ActiveRecord::Base
has_many :archive_object_people
has_many :people, :through => :archive_object_people
class ArchiveObjectPerson < ActiveRecord::Base
belongs_to :archive_object
belongs_to :person
class Person < ActiveRecord::Base
has_many :archive_object_people
has_many :archive_objects, :through => :archive_object_people
我还在模型中创建了一些范围和方法来帮助我。 在archive_object.rb中
# These can be used to distinguish recipients from creators of letters
# Use case: ArchiveObject.first.creators
def recipients
people.where("archive_object_people.persontype = '1'")
end
def creators
people.where("archive_object_people.persontype = '0'")
end
scope :recipients, lambda {
joins(:people).where("archive_object_people.persontype = '1'")
}
scope :creators, lambda {
joins(:people).where("archive_object_people.persontype = '0'")
}
我想预加载创建者和接收者,就像我包含字母的位置一样,这样我就可以遍历每个字母并显示 letter.title、letter.creators、letter.collection 等,而无需运行数十个查询。例如:ArchiveObject.includes(:collections, :creators)
到目前为止我已经尝试过的事情。所有这些都将在获取收件人/创建者时运行另一个查询,尽管他们在查看通用“人”时可能不会运行另一个查询:
ArchiveObject.joins(:people).where("archive_object_people.persontype = '1'").preload(:people)
ArchiveObject.includes(:people, :archive_object_people).first.recipients
ArchiveObject.includes(:recipients) => raises an exception
我还开始阅读有关重新定义 has_many 并使用条件仅拉动创建者或接收者的文章,但实际上我需要两个关联,在这种情况下:一个 has_many 创建者和一个 has_many 接收者。我不知道如何设置,但如果有人有任何想法,那就太棒了。
感谢您给我的任何帮助或建议!我很想弄清楚这一点,以便我拥有一个超级快速和高效的网站。 :)
【问题讨论】:
标签: sql ruby-on-rails optimization eager-loading