7

我正在编写一个 Web 应用程序来监控家具厂的生产流程。它有数千个数据要处理。到目前为止,我在 Mongrel + MySQL 上运行 RoR,它真的很慢(某些视图需要 2-4 分钟)。当我查看 RoR 日志时,数据库查询似乎并不慢(0-10 毫秒)。

RoR 将数据库数据转换为对象时速度慢吗?杂种很慢吗?

编辑:第一件事:我在开发。环境。在生产环境中,最慢的视图需要 2 分钟(在一台好计算机上会降低到不到 1 分钟,我的是 5 岁)。借助 ruby​​-prof 和一些常识,我发现了哪些方法会降低应用程序的速度。问题是在大型数据集上循环调用单个 SQL 查询:

ofs = Ofkb.find_by_sql ["..some large SQL query..."]

for of in ofs # About 700-1000 elements
   ops = Operation.find(..the single query..)
   etc.
end

以下是这些方法的 ruby​​-prof 结果:

 %self     total     self     wait    child    calls  name
 32.19     97.91    97.91     0.00     0.00       55  IO#gets (ruby_runtime:0}
 28.31     86.39    86.08     0.00     0.32    32128  Mysql#query (ruby_runtime:0}
  6.14     18.66    18.66     0.00     0.00    12432  IO#write (ruby_runtime:0}
  0.80      2.53     2.42     0.00     0.11    32122  Mysql::Result#each_hash (ruby_runtime:0}

问题是:我无法真正避免那些单一的查询。我有数以千计的事件,我必须从中计算复杂的数据。现在我在那些没问题的方法上使用 memcached,除非你是第一个请求页面的人。

4

11 回答 11

17

我会同意其他所有人的观点。你必须配置文件。在您知道具体是什么导致缓慢之前,对您的代码做任何事情都是没有意义的。试图在不了解原因的情况下解决问题就像感觉不适并决定进行大量手术直到您感觉好些。首先诊断你的问题。它可能是网络设置之类的小东西,也可能是代码中的错误行。

分析的一些提示:

如何分析您的 Rails 应用程序

性能测试 Rails 应用程序

At the Forge - 分析 Rails 应用程序

一旦你找到了瓶颈,你就可以弄清楚该怎么做。

我推荐这些视频: Railslab Scaling Rails

现在根据教授结果修订:

好的。现在您可以看到您的问题是您正在使用基于循环通过另一个活动记录查询的结果的查询进行某种计算,我建议您考虑构建一个自定义 SQL 语句,结合您的初始选择条件和循环计算以获得你需要的东西。您绝对可以通过优化 SQL 来加快速度。

于 2009-02-20T09:38:56.577 回答
5

每个视图访问执行了多少个 0-10 毫秒的查询?引用了数据模型的哪些部分?您是否正在使用 :include 来获得对关联的渴望加载?

Rails 和你做的一样慢。理解带来速度(通常!)

扩展上述内容,您是否有 has_many 关联,特别是,您的视图引用没有 ? 的“多”方:include?这会导致您find(:all)在主表上执行与详细信息的连接 - 如果您有大量详细记录并且正在单独处理所有这些记录,这可能会变得昂贵。

像这样的东西:

Master.find(:all, :include => :details)

...可能有帮助。不过,仍然从稀疏的信息中猜测。

这里有一个关于这个主题的旧 Railscast

于 2009-02-19T18:01:48.927 回答
5

虽然 RnR以速度慢着称,但这听起来太极端了,不能成为语言的简单问题。

您应该运行探查器来准确确定哪些函数很慢以及为什么。最常见的拖慢 Web 应用程序的是“ n+1 问题”。也就是说,当您的数据库中有 n 个数据项时,应用程序会对数据库进行 n 个单独的查询,而不是通过一个查询来获取它们。但是在您运行分析器之前,您无法知道。ruby-prof是我用过的一种分析器。

根据配置文件结果编辑:

我坚信您始终可以删除查询循环。正如 Mike Woodhouse 所说,Rails 的做法是使用has_many或其他关联指定表之间的关系,然后让 rails 自动生成表连接,这是清晰、快速和“Rails 方式”。但是,如果您从裸 SQL 开始,或者如果关联在这种情况下不起作用,您可以简单地自己生成适当的连接。如果一切都失败了,您可以创建一个视图或非规范化表,其中包含以前通过循环找到的结果。事实上,您必须遍历生成的查询这一事实可能表明您的表设计本身存在一些缺陷。

综上所述,如果缓存查询结果对您来说足够好,那么请继续使用它。需要时进行优化。

于 2009-02-19T18:08:48.787 回答
4

这不正常。你有一些让你慢下来的逻辑。尝试注释掉您认为需要很长时间的代码片段,看看是否有帮助。如果是这样,那么您需要弄清楚如何优化该逻辑。

如果您在一个循环中迭代大量对象进行大量计算,那么它当然会很慢。

这些类型的问题可以在任何语言或框架中出现。虽然 Ruby 没有其他语言那么快,但在大多数情况下它已经足够快了。如果您需要不断地使用大型数据集进行计算,那么 Ruby 可能不适合您。考虑编写一个 Ruby C 扩展来处理你的性能消耗代码。但首先只是尝试诊断和重构。

最后,查看RubyProf看看它是否可以帮助您找到瓶颈。

于 2009-02-19T17:56:59.117 回答
3

前两个答案很有帮助,尤其是使用性能监控工具。我使用New Relic RPM,它在过去帮助了我很多。

但是,当您试图从 3 秒加速到 1 秒以下时,这些工具确实是最好的。

在任何正常情况下,一个视图渲染 2-4 分钟是绝对不正常的。

您能否向我们展示您的一些开发日志以找出瓶颈所在?

您是否将浏览器加载图像、javascript 或其他文件所需的时间计算在内?

于 2009-02-19T18:07:15.073 回答
0

这么长的执行时间会让我怀疑网络问题 - 也许 DNS 查询在主 DNS 服务器上超时?

于 2009-02-19T18:13:06.257 回答
0

您可以尝试使用 JRuby 或切换到 Ruby 1.9。
它们都应该会带来巨大的性能提升。
JRuby 的问题是使用 C 的 gem 无法编译/工作。jruby 的“gem”应用程序安装了 Java 等效项,但有些 gem 根本不起作用

Ruby 1.9 基本上会有同样的问题。语法发生了一些变化,但主要问题是大量的 gem 不再起作用。人们正在进行更新(在http://isitruby19.com/查看进度)

于 2009-02-19T20:18:53.600 回答
0

为什么不预先获取所有数据并让您的 for 循环在内存中本地找到它,而不是每次都查询数据库?对单个视图的 1000 次查询表明您的设计存在严重问题。

于 2009-02-20T20:18:48.177 回答
0

关于这个主题有一些很好的屏幕截图http://railslab.newrelic.com/scaling-rails

像片段缓存和使用 :include (以避免 n+1)这样的事情会有所帮助。听起来您已经在使用 memcached,那么为什么不 curl url 来预取缓存呢?

于 2009-02-25T11:19:15.640 回答
0

当我将服务器绑定到盒子 IP 地址而不是 0.0.0.0 时,这加快了我的速度。

于 2010-11-11T17:52:59.337 回答
0

您可以在执行任何操作之前先对代码进行分析,但是,for 循环内部的查询是导致性能问题的一个非常常见的原因,乍一看这似乎是您的问题。无论如何,您可能会在这里找到一个实用的分析器:

正如在其他答案中已经说过的,如果两个模型都是相关的,您应该预先加载关联,这意味着指示 Active Record 执行连接查询:

#left outer join
ofkbs=Ofkb.includes(:operation).where(name: "banana")

如果您不需要 ofkbs 而只需要操作,则可以执行内部连接

#inner join (discards the Ofkbs that do not have any operation)
operations=Operation.joins(:ofkb).where(ofkb:{name:"banana"})

此解决方案仅执行一个查询,并允许您随后遍历已经从数据库中收集的数据:

operations=ofkbs.map{|of| of.operations}.flatten

operations.each do |o|
  do_whatever_you_want_with_operation(o)
end

如果查询非常复杂,您应该改用arel

于 2014-07-23T10:33:45.370 回答