我整天都在尝试重构我的查询。加载一个包含 20 条记录的表需要几分钟时间。起初,我在这个 stackoverflow 帖子中指责了查询:
然而,在做了一些测试之后,我意识到查询加载非常快,并不是罪魁祸首。
然后我把它归咎于 kaminari,因为我认为 kaminari 正在将数千条记录填充到 ruby 对象中,正如我在这篇文章中解释的那样:
但这也是错误的。Kaminari 一次只加载 20 条记录(我使用记录器检查加载了多少报告,结果显示为 20 条)。
所以最后我想我找到了真正的罪魁祸首。这是在该页面的分页期间发生的另一个查询。我意识到这个查询每次运行都需要 20 多秒的时间来加载:
def virtual_fence_duration
inside_fence_time = nil
outside_fence_time = nil
outside_fence_time = self.time
previous_reports = Report.where{(time < my{self.time}) &
(unit_id == my{self.unit_id})}.order('time desc')
previous_reports.each do |report|
alerts = report.alerts.collect { |a| a.code_name }
if alerts.include? "Inside virtual fence"
inside_fence_time = report.time
break
end
end
if inside_fence_time && outside_fence_time
"Virtual Fence Elapsed Time: #{(((outside_fence_time - inside_fence_time).to_i).to_f/60.0).ceil} minutes"
else
""
end
end
基本上,当存在“超出虚拟围栏”的警报时,会调用此方法。我存储时间。然后我查询之前的所有报告(报告 has_many 警报)。然后我使用 ruby 的每个迭代器来遍历每个报告,然后使用与这些报告关联的警报来查找“在虚拟围栏内”的警报。然后我存储该报告的时间并取两者之间的差异。如果在两个持续时间之间有很多报告,这种逻辑似乎会永远持续下去。在 sql (mysql) 或 ruby 中是否有更有效的方法来执行此操作?