【问题标题】:Rails 4 A Faster way to list all records in ModelRails 4 列出模型中所有记录的更快方法
【发布时间】:2014-07-02 03:15:16
【问题描述】:

我有一个 Products 模型,其中包含 6,000 条记录(不多)。当我在视图中运行循环以简单地列出表中的所有记录时,类似于此..

<% Product.all.each do |product|  %>
   <%= product.serial_number %> <br />
<% end %>

它需要 13.02 秒才能加载到我的视图中并在网页中显示我的记录。这在我的 dev ENV 和 prod ENV 中都有,我尝试使用 MySQL 和 sqlite 数据库。好像没什么区别。

但是,当我在 rails 控制台中运行此查询时,它会在 88.2 毫秒(不到 1 秒)内完成。

这是什么原因造成的?

【问题讨论】:

  • 你和这个模型有关联吗?
  • 是的,我实际上大约有 8 个。其中6个是belongs_to:,其中2个是has_many:关联。现在您提出了这个问题,我看到很多与它们相关的 SQL 正在运行。它是否查找每一行的每个关联?
  • 是的。在下面查看我的详细答案

标签: jquery ruby-on-rails performance


【解决方案1】:

加入

最重要的是你必须加入可以加入的协会。查看您的服务器日志,看看您何时显示该页面,如果您有很长的数据库获取列表。例如,如果您的 ProductUser 相关联,您将看到您的产品列表有一个“SELECT”,然后您的用户会看到数百个“SELECT”。您可能想要使用此语法

<% Products.joins(:user).each do |product|  %>
  <%= product.serial_number %> <br />
<% end %>

请注意,您必须适应您的代码(我以user 为例),这完全取决于您的关联。在指南中查看更多信息here

请注意,joins 执行“INNER JOIN”,并将删除所有具有 nil 引用的记录。如果是您的情况,您可以通过includes 使用“急切加载”技术:

Products.includes(:user).each do |product|

Find_each

或者,尝试使用find_each,它将分批处理您的记录以节省服务器电源。在guides中查看有关它的更多详细信息

Products.find_each do |product| 

缓存

您可以选择使用caching 来提高性能

Products.find_each do |product|
  cache product do
    ...
  end
end

分页

如果可能的话,还可以考虑使用分页来限制从数据库中获取的记录数

【讨论】:

  • 谢谢本杰明。当我添加 和 标记时,我收到以下错误:语法错误,意外的关键字_确保,期望输入结束
  • 我的错,我忘记了do(编辑了我的答案)。无论如何,我想您可以直接跳到“加入”一章,因为根据您的最后评论,这似乎是您查询缓慢的主要原因
  • 感谢您的澄清。添加要显示的所有列后,我的查询在视图中花费了大约 32 秒。添加这个改进到大约 11,这很棒。但是对于 6000 条记录来说,这仍然是很长的时间吗?我一直认为 Rails 足够强大,最多只能在几秒钟内加载这几条记录。
  • 很难说,很多因素都会影响速度,例如数据库记录的正确索引、缓存后端的速度等......谷歌应该为您的案例提供一些有用的信息跨度>
【解决方案2】:

你只追求一个领域?使用pluck。这正是它的用途。

<% Products.pluck(:serial_number).each do |serial_number| %>
   <%= serial_number %> <br />
<% end %>

这既可以生成更高效的 SQL(select serial_number 而不是 select *),也可以绕过为每个返回的结果实例化 ActiveRecord 对象的步骤,以便您可以访问该模型的单个属性。

但是,当我在 rails 控制台中运行此查询时,它会在 88.2 毫秒(不到 1 秒)内完成。

除非您真正开始迭代结果,否则 Rails 不会任何事情。只有当您尝试访问结果时,Rails 才会实际实例化记录。


回复:您的评论

但是,我实际上只是将上述内容作为示例。我实际上是在显示每条记录的所有字段。有什么技巧吗?

那么,您不应该使用循环,如您的示例所示。使用 partials 和 collection rendering,这比自己迭代结果快得多

创建一个名为app/views/products/_product.html.erb 的视图,并将循环的“主体”放入该文件中。它可能看起来像这样:

<div class="product">
  Name: <%= link_to product, product.name %><br/>
  Serial Number: <%= product.serial_number %>
</div>

然后,在顶级视图中,使用该部分渲染整个集合:

render partial: 'product', collection: Product.all

【讨论】:

  • 我得到这个:#:0x00000109060d10> 的未定义局部变量或方法`product'
  • 取决于您的模型的名称。
  • 这是一个产品模型hmmmm
  • 你不应该有一个名为“产品”的模型。它应该是“产品”。这是 Rails 中一个非常重要的论点,除非你有非常好的理由不这样做,否则你应该坚持它。
  • 抱歉确实是Product.rb模型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-30
  • 1970-01-01
相关资源
最近更新 更多