我正在编写一个Web应用程序来监控家具厂的生产流程。它有数千个数据需要处理。到目前为止,我在Mongrel + MySQL上运行RoR并且它真的很慢(对于某些视图为2-4分钟)。当我查看RoR日志时,似乎数据库查询速度不慢(0-10ms)。
将数据库数据转换为对象时,RoR是否会变慢? Mongrel慢了吗?
编辑:第一件事:我在开发中。 ENV。在生产环境中,最慢的视图需要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,除非你是第一个请求页面的人。
答案 0 :(得分:17)
我会同意其他人的意见。你必须剖析。在您知道具体导致缓慢的原因之前,对代码执行任何操作都没有意义。试图在不了解原因的情况下解决问题,就像感觉不舒服,并决定在感觉好转之前进行大量手术。首先诊断您的问题。它可能像网络设置一样小,也可能是代码中的一条坏线。
分析的一些提示:
How to Profile Your Rails Application
Performance Testing Rails Applications
At the Forge - Profiling Rails Applications
一旦找到瓶颈,你就可以弄明白该怎么做了。
我推荐这些视频: Railslab Scaling Rails
现在根据教授结果进行修订:
行。既然您可以看到您的问题是您正在使用基于循环查看另一个活动记录查询结果的查询进行某种计算,我建议您研究构建一个自定义SQL语句,结合您的初始选择标准和获得你需要的循环计算。你可以通过优化SQL来加快速度。
答案 1 :(得分:5)
每个视图访问权限执行了多少0-10ms查询?您的数据模型的哪些部分被引用?您是否正在使用:include以获得对您的关联的热切加载?
Rails和你做的一样慢。了解速度(通常!)
扩展上面的内容,你是否有has_many关联,特别是你的视图在没有:include
的情况下引用了“很多”方面?这会导致主表上的find(:all)
通过连接到详细信息来执行 - 如果您有大量的详细记录并且正在单独处理所有这些记录,这可能会变得很昂贵。
这样的事情:
Master.find(:all, :include => :details)
......可能有所帮助。但仍然从稀疏信息中猜测。
主题here
上有一个旧的Railscast答案 2 :(得分:5)
虽然R-n-R has a reputation of being slow,但这听起来太极端而不是语言的简单问题。
您应该运行一个分析器来确定哪些功能很慢以及原因。减慢Web应用程序最常见的是“n+1 problem”。也就是说,当您的数据库中有n个数据项时,该应用程序会对数据库进行单独的查询,而不是进行一次获取它们的查询。但在运行探查器之前,您无法知道。 ruby-prof是我用过的一个分析器。
根据个人资料结果编辑进行编辑:
我坚信您可以 始终 删除查询循环。正如Mike Woodhouse所说,Rails的方法是使用 has_many 或其他关联来指定表之间的关系,然后让rails自动生成表连接,这很清楚,快速和“Rails方式”。但是如果你刚开始使用裸SQL,或者在这种情况下关联不起作用,你可以自己生成适当的连接。如果所有其他方法都失败了,您可以创建一个视图或非规范化表,其中包含先前通过循环找到的结果。实际上,您必须遍历生成的查询的事实可能表明您的表设计本身存在一些缺陷。
所有这一切,如果缓存您的查询结果对您来说效果很好,那么请坚持下去。在需要时进行优化。
答案 3 :(得分:4)
这不正常。你有一些让你失望的逻辑。尝试评论您认为需要花费很长时间的代码的一些部分,看看是否有帮助。如果确实如此,那么你需要弄清楚如何优化这种逻辑。
你在迭代大量对象的循环中做了很多计算,当然它会很慢。
这些类型的问题可以出现在任何语言或框架中。虽然Ruby没有其他语言那么快,但它在大多数时候都足够快。如果您需要不断计算大型数据集,那么Ruby可能不适合您。研究编写一个可以处理性能耗尽代码的Ruby C扩展。但首先只是尝试诊断和重构。
最后,请查看RubyProf,了解它是否可以帮助您找到瓶颈。
答案 4 :(得分:3)
前两个答案很有帮助,尤其是使用性能监控工具。我使用New Relic RPM并且它在过去帮助了我很多。
然而,当你试图从3秒加速到1秒以下时,这些工具真的是最好的。
在任何正常情况下,渲染视图2-4分钟绝对不正常。
您能否向我们展示一些开发日志,以找出瓶颈所在?
您是否包括浏览器将图像,javascripts或其他文件加载到此总测量中所需的时间?
答案 5 :(得分:0)
这么长的执行时间会让我怀疑网络问题 - 也许DNS查询在主DNS服务器上超时?
答案 6 :(得分:0)
您可以尝试使用JRuby或切换到Ruby 1.9 它们都应该会带来巨大的性能提升 JRuby的问题是使用C的gem不会编译/工作。 jruby的“gem”应用程序安装了Java等价物,但有些宝石根本无法使用
Ruby 1.9基本上会遇到同样的问题。一点点的语法改变了,但主要的问题是,大量的宝石不再起作用了。人们正在进行更新(检查http://isitruby19.com/处的进度)
答案 7 :(得分:0)
为什么不预先获取所有数据并让你的for循环在内存中找到它,而不是每次都查询数据库?单个视图的1000次查询表明您的设计严重错误。
答案 8 :(得分:0)
此主题http://railslab.newrelic.com/scaling-rails
有一些很好的屏幕演员像fragmet缓存和使用:include(避免n + 1)之类的东西可以提供帮助。听起来你已经在使用memcached了,那么为什么不卷曲url来预取缓存呢?
答案 9 :(得分:0)
当我将服务器绑定到盒子ip地址而不是0.0.0.0时,这为我加速了。
答案 10 :(得分:0)
在执行任何操作之前,您可能会首先分析代码,但是,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代替。