我有一个RoR应用程序,其中包含一个用于管理应用程序的API,每个应用程序都包含配方(以及组,成分,测量值)。
用户完成配方管理后,会下载整个应用程序的JSON文件。因为每个应用程序可能有数百个配方,所以文件可能很大。这也意味着需要进行大量的数据库调用才能获得所有需要的数据。
现在因此,下载应用程序的请求可能需要30秒,有时甚至更多。
我当前的代码看起来像这样:
application.categories.each do |c|
c.recipes.each do |r|
r.groups.each do |r|
r.ingredients.each do |r|
在每个循环中,我将数据存储在HASH中,然后将其提供给用户。
我的问题是:我从哪里开始?
答案 0 :(得分:1)
当然有一些方法可以同时获取更多数据。这是通过Rails includes
或joins
完成的,具体取决于您的需求。有关详细信息,请参阅this article。
基本思想是您可以在表之间加入,以便每次都不生成新查询。执行application.categories
时,这是一个查询。对于每个类别,您将执行另一个查询:c.recipes
- 这会创建N + 1个查询,其中N是您拥有的类别数。相反,您可以将它们包括在内,以创建1或2个查询(取决于Rails的功能)。
基本语法很简单:
Application.includes(:categories => :recipes).each do |application| ...
这会生成1(或2 - 再次,请参阅文章)查询,该查询一次性抓取所有应用程序,其类别和每个类别的收件人。你也可以对这些团体和成分进行研究。
至于把工作放在后台,我的建议是只有一个加载图像,或者通过使用进度条来获得幻想。
答案 1 :(得分:1)
首先,我必须假设存在所需的has_many
和belongs_to
关联。
通常你可以做类似
的事情c.recipes.includes(:groups)
甚至
c.recipes.includes(:groups => :ingredients)
将立即获取食谱和组(和成分)。
但是,由于你有一个非常大的数据集IMO,如果你将这种技术限制在最深层次会更好。
最有用的方法是同时使用find_each和includes
。
(find_each
批量提取项目以保持内存使用率低)
或许类似
application.categories.each do |c|
c.recipes.find_each do |r|
r.groups.includes(:ingredients).each do |r|
r.ingredients.each do |r|
...
end
end
end
end
现在即使这可能需要相当长的时间(对于http请求),因此您可以考虑使用一些异步处理,其中客户端将生成将由服务器作为后台作业处理的请求,并且当准备就绪,您可以提供下载链接(或发送电子邮件)给客户。
Resque是处理异步部分的一种可能解决方案。