这种热切的装载是否正在做我认为应该做的事情?

时间:2013-06-19 12:25:34

标签: ruby-on-rails activerecord eager-loading

我刚刚在competitors_controller.rb中更改了某个操作...

def audit
  @review = Review.find(params[:review_id])
  @competitor = @review.competitors.find(params[:id])
  respond_with(@review, @competitor)
end

...到...

def audit
  @review = Review.find(params[:review_id])
  @competitor = Competitor.find(params[:id], :include => {:surveys => {:question => [:condition, :precondition]}})
  respond_with(@review, @competitor)
end

...因为页面在加载时超时。

潜在的关联是:

class Competitor < ActiveRecord::Base
  has_many :surveys
end

class Survey < ActiveRecord::Base
  belongs_to :competitor
  belongs_to :question
  delegate :dependencies, :precondition, :condition, :to => :question  
end

class Question < ActiveRecord::Base
  has_many :dependancies, :class_name => "Question", :foreign_key => "precondition_id"
  belongs_to :precondition, :class_name => "Question"
  has_many :surveys, :dependent => :delete_all
end

基本上,audit.html.haml页面加载:

 @competitor.surveys.{sorting, etc}.each do |s|
    s.foo, s.bar
    s.{sorting, etc}.dependant_surveys.each do |s2|
       s2.foo, s2.bar
       s2.{sorting, etc}.dependant_surveys.each do |s3|
           s3.foo, s3.bar, etc etc

如果我将它嵌套得太远,页面就会在超时之前加载。

我需要知道的是,我在competitor_controllers.rb中插入的热切加载是否理论上加快了以下两种方法中的每一种方法,这些方法在构建audit.html.haml时经常被调用?

class Survey < ActiveRecord::Base
  def dependant_surveys
    self.review.surveys.select{|survey| self.dependencies.include?(survey.question)}
  end
end

class Question < ActiveRecord::Base
  def dependencies
    Question.all.select{|question| question.precondition == self}
  end
end

(我说“理论上”,因为我知道这个问题也可以通过基准测试来回答。但在我达到目标之前,我想检查一下我的理论是否正确。)

3 个答案:

答案 0 :(得分:1)

热切的加载看起来应该可以工作,但更重要的是,这些是你可以而且应该使用SQL做的事情。加载和迭代数据库中的所有ActiveRecord模型可能非常耗时(如您所见),而在SQL中如何进行操作将允许您直接从单个查询加载所有模型。掌握这个可能需要一段时间,但这非常值得!

答案 1 :(得分:1)

你在ruby中做了很多处理,没有必要这样做。您应该移动所有操作,如

Question.all.select{|question| question.precondition == self}
@competitor.surveys.{sorting, etc}

到数据库。

如果我理解正确,第一行是为了选择所有具有前置条件设置为给定问题的记录。请记住,Question.all返回一个数组,因此您在数组中执行select,并且您可以在db中使用简单范围scope :has_precondition, -> {|q| where(precondition_id: q.id}左右执行此操作。

鉴于您总是以相同的方式对模型进行排序,您可以考虑使用order子句创建默认范围。在ruby中执行它非常有效。

答案 2 :(得分:0)

据我所知,您只能包含急切加载的关联。我不认为你拥有的东西会起作用。您尚未向我们展示定义Question.condition的位置,或Survey.review。此外,当您正在执行自己的查询时,您的方法dependent_surveysdependencies将不会使用您急切加载的关联。

AFAICT你急切的加载不会造成很大的不同,或者它可能会减慢速度。我认为你必须重构你的dependent_surveys作为一种关联和渴望加载。我没有丝毫的线索,这个方法试图在高层次上做什么,所以我甚至都不会尝试重构它。