如果凌乱的控制器更快,为什么最好使用Rails范围?

Ste*_*ner 5 activerecord ruby-on-rails arel named-scopes

我一直在尝试使用范围来链接Arel查询,而不仅仅是使用我在控制器中编写的一些冗长的逻辑。但是作用域比仅获取所有记录然后用某种逻辑筛选它们要慢。那么,我想知道为什么范围会更好。

这是我在做什么:

  • 一个问题有很多答案
  • 一个答案属于一个问题
  • 一个问题具有“ question_type”列,该列用于对其进行排序

首先,作用域方式

issue.rb:

scope :answered, joins(:answers).order('answers.created_at desc')
scope :dogs, where(:question_type => "dogs")
scope :cats, where(:question_type => "cats")
scope :mermaids, where(:question_type => "mermaids")
Run Code Online (Sandbox Code Playgroud)

在questions_controller.rb中:

@dogs_recently_answered = Question.answered.dogs.uniq[0..9]
@cats_recently_answered = Question.answered.cats.uniq[0..9]
@mermaids_recently_answered = Question.answered.mermaids.uniq[0..9]
Run Code Online (Sandbox Code Playgroud)

然后在视图中,循环浏览这些实例变量(现在是最多包含10个元素的数组)并显示结果。

以下是加载页面所需的时间(五个不同的时间):

在535毫秒内完成200 OK(查看:189.6毫秒| ActiveRecord:46.2毫秒)

在573毫秒内完成200 OK(查看:186.0毫秒| ActiveRecord:46.3毫秒)

在577毫秒内完成200 OK(查看:189.0毫秒| ActiveRecord:45.6毫秒)

在532毫秒内完成200 OK(查看:182.9毫秒| ActiveRecord:46.1毫秒)

在577毫秒内完成200 OK(查看:186.7毫秒| ActiveRecord:46.9毫秒)

现在,凌乱的控制器方式...

@answers = Answer.order("created_at desc")
@all_answered = []
@answers.each {|answer| @all_answered << answer.question}
@recently_answered = @all_answered.uniq
@dogs_all_answered = []
@cats_all_answered = []
@mermaids_all_answered = []
@recently_answered.each do |q|
  if q.question_type == "dogs"
    @dogs_all_answered << q
    @dogs_recently_answered = @dogs_all_answered[0..9]
  elsif q.question_type == "cats"
    @cats_all_answered << q
    @cats_recently_answered = @cats_all_answered[0..9]
  elsif q.question_type == "mermaids"
    @mermaids_all_answered << q
    @mermaids_recently_answered = @mermaids_all_answered[0..9]
  end
end
Run Code Online (Sandbox Code Playgroud)

这是现在加载页面所需的时间(五个不同的时间):

在475毫秒内完成200 OK(查看:196.5毫秒| ActiveRecord:34.5毫秒)

在480毫秒内完成200 OK(查看:200.4毫秒| ActiveRecord:36.4毫秒)

在434毫秒内完成200 OK(查看:198.2毫秒| ActiveRecord:35.8毫秒)

在475毫秒内完成200 OK(查看:194.2毫秒| ActiveRecord:36.4毫秒)

在475毫秒内完成200 OK(查看:195.0毫秒| ActiveRecord:35.4毫秒)

所以...

除了可读性之外,通过将查询与作用域匹配可以赢得什么?当有更多记录时,它最终会变得更快吗?

jxp*_*777 5

首先,我不确定我是否理解除了唯一性问题之外的其他问题,因此我将尝试删除该问题。我不知道您数据的逻辑,因此这可能不适用,但这是您可以避免的额外步骤。

这是我的处理方法:

scope :answered, joins(:answers).order('answers.created_at desc')
scope :recent, take(10)
scope :dogs, where(:question_type => "dogs")
scope :cats, where(:question_type => "cats")
scope :mermaids, where(:question_type => "mermaids")

@dogs_recently_answered = Question.answered.dogs.recent
@cats_recently_answered = Question.answered.dogs.recent
@mermaids_recently_answered = Question.answered.dogs.recent
Run Code Online (Sandbox Code Playgroud)

这会将TOP查询的一部分转移到查询所属的数据库,而不是获取所有行,然后丢弃除10 之外的所有行。根据唯一性条件,您还可以使用如下范围

scope :unique, select('DISTINCT column_name')
Run Code Online (Sandbox Code Playgroud)

然后您可以使用Question.cats.unique.recent并通过一个快速查询来获取所有信息,该查询利用了数据库系统所设计的关系代数。