【问题标题】:Ruby On Rails is slow...?Ruby On Rails 很慢...?
【发布时间】:2010-10-08 15:50:53
【问题描述】:

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

将数据库数据转换为对象时,RoR 是否很慢? Mongrel 慢吗?

编辑:第一件事:我在开发。环境。在生产环境中,最慢的视图需要 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,除非你是第一个请求页面的人。

【问题讨论】:

  • 也不是,可能是您编写的代码速度慢,或者您在开发中运行在生产环境中。如果您可以发布适当的视图内容,我们也许可以给出正确的答案。
  • 同意@Tomh - 这一点都不典型,即使是大型数据集。我们需要更多信息才能做出任何类型的诊断。
  • 这听起来可能很愚蠢,但请确保您在生产模式下运行。开发模式将在每次请求时重新加载所有类。
  • 第一件蠢事:我在开发环境中。切换到生产,性能更好但仍然不能接受。我正在寻找可能会降低应用程序速度的错误逻辑。

标签: mysql ruby-on-rails ruby mongrel


【解决方案1】:

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

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

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

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

【讨论】:

  • “首先,检查 ruby​​prof”不是更好吗
  • 为什么你的分析方法是注释掉代码的点点滴滴,而不是使用分析器的科学技术?
【解决方案2】:

虽然 R-n-R has a reputation of being slow,这听起来太极端了,不可能是语言的简单问题。

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

根据个人资料结果编辑:

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

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

【讨论】:

  • 对不起--1 是我。没有引用“R-n-R”(?)很慢,根据我的经验,这似乎是有争议的、不必要的以及不真实的。
  • 没有引用,但这是一个相当普遍的观点,不管是真是假。
【解决方案3】:

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

正如在其他答案中已经说过的,如果两个模型都相关,您应该预先加载关联,这意味着指示 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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

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

      片段缓存和使用 :include (避免 n+1)之类的东西会有所帮助。听起来你已经在使用 memcached 了,为什么不 curl url 来预取缓存呢?

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

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

          分析的一些技巧:

          How to Profile Your Rails Application

          Performance Testing Rails Applications

          At the Forge - Profiling Rails Applications

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

          我推荐这些视频: Railslab Scaling Rails

          现在根据教授结果进行了修订:

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

          【讨论】:

            【解决方案8】:

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

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

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

            类似这样的:

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

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

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

            【讨论】:

              【解决方案9】:

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

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

              【讨论】:

                【解决方案10】:

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

                【讨论】:

                  【解决方案11】:

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

                  但是,当您尝试将速度从 3 秒缩短到 1 秒以下时,这些工具确实是最好的。

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

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

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

                  【讨论】:

                  • 是的,New Relic 非常适合追踪这些东西。
                  猜你喜欢
                  • 1970-01-01
                  • 2018-11-27
                  • 2014-09-27
                  • 2010-12-29
                  • 1970-01-01
                  • 2012-10-01
                  • 2013-02-24
                  • 2015-10-05
                  • 2013-07-26
                  相关资源
                  最近更新 更多