如果凌乱的控制器更快,为什么轨道示波器是可取的?
-
29-09-2019 - |
题
我一直在尝试使用示波器链接Arel查询,而不仅仅是使用我在控制器中写的一些漫长的逻辑。但是,范围比仅获取所有记录,然后用一些逻辑筛选它们慢。我想知道,为什么范围更好。
这是我在做的事情:
- 一个问题有很多答案
- 答案属于一个问题
- 一个问题具有我用来对其进行排序的“ Question_type”列
首先,范围...
在问题上: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")
在Question_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]
然后,在视图中,我循环浏览那些实例变量(现在最多包含10个元素的数组)并显示结果。
这是加载页面所需的时间(五个不同的时间):
在535ms中完成200个OK(视图:189.6ms | ActivereCord:46.2ms)
在573ms中完成了200个OK(视图:186.0ms | ActivereCord:46.3ms)
在577ms中完成了200个OK(视图:189.0ms | ActivereCord:45.6ms)
在532ms中完成了200个OK(视图:182.9ms | ActivereCord:46.1ms)
在577ms中完成了200个OK(视图:186.7ms | ActivereCord:46.9ms)
现在,凌乱的控制器方式...
@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
这是立即加载页面所需的时间(五个不同的时间):
在475ms中完成200个OK(视图:196.5ms | Activerecord:34.5ms)
在480ms中完成了200个OK(视图:200.4ms | ActivereCord:36.4ms)
在434ms中完成了200个OK(视图:198.2ms | Activerecord:35.8ms)
在475ms中完成了200个OK(视图:194.2ms | ActivereCord:36.4ms)
在475ms中完成了200个OK(视图:195.0ms | ActivereCord:35.4ms)
所以...
除了可读性之外,通过使用范围来磨练查询,还可以赢得什么?当有更多记录时,它最终会变得更快吗?
解决方案
首先,我不确定我明白一个问题如何是唯一的,所以我要尝试删除这个问题。我不知道您的数据逻辑,因此可能不适用,但这是您可能避免的额外步骤。
这是我将如何处理的方式:
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
这改变了 TOP
查询的一部分到数据库所属的数据库而不是获取 全部 排在行,然后丢弃除10。
scope :unique, select('DISTINCT column_name')
然后,您可以使用Question.cats.unique.RECENT,并在一个快速查询中获取所有利用数据库系统设计的关系代数的快速查询。
其他提示
我认为在这种情况下,范围较慢的原因是因为它们产生了3个单独的数据库查询,而另一种方法则使用了以下知识:您使用的单个查询可以满足所有三个结果。
假设是这种情况,范围正在执行3个单独的查询也就不足为奇了,因为系统不知道您何时调用第一个疑问,然后再打电话给其他问题。也许有一种优化策略对于这种情况是明智的,但我不知道ActivereCord实现了它。
无论如何,这是这种特殊情况下范围的缺点。我喜欢示波器,因为它们是干净/清晰,灵活的,并封装了一个命名的抽象。 Afaict,在许多情况下,它们并不比等效的直接查询要慢。