Ruby On Rails is slow…?

2019-03-09 05:40发布

I'm writing a web application to monitor a furniture factory production flow. It has thousand of data to handle. So far, I run RoR on Mongrel + MySQL and it's really really slow (2-4min for some views). When I look at RoR logs, it seems that database queries aren't slow (0-10ms).

Is RoR slow when it converts database data to object ? Is Mongrel slow ?

Edit: First thing: I was in dev. env. In production environment, the slowest view takes 2min (which would turn down to less than 1min on a good computer, mine is 5 years old). With ruby-prof and a bit of common sense, I've found out which methods were slowing down the application. The problem is that single sql queries are called in loops on larges datasets:

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

Here are ruby-prof results on those methods:

 %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}

Problem is: I can't really avoid those single queries. I've got thousand of events from which I have to compute complex data. Right now I'm using memcached on those methods which is OK unless your the first to request the page.

11条回答
forever°为你锁心
2楼-- · 2019-03-09 06:06

You might profile the code first before doing anything, though, queries inside for loops are a very common cause for performance problems and at first sight this seems your problem. You might anyway find a practical profiler here:

As already said on the other answers, if both models are related you should eager load the associations, which implies instructing Active Record to perform join queries:

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

If you do not need the ofkbs but only the operations, you could perform an inner join

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

This solution only preforms one query, and allows you to afterwards iterate through the data that will have already been collected from the DB:

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

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

If the queries are very complicated you should use arel instead.

查看更多
冷血范
3楼-- · 2019-03-09 06:09

I'll agree with everyone else. You have to profile. There is no point in doing anything to your code until you know what specifically is causing the slowness. Trying to fixing a problem without understanding the cause is like feeling ill and deciding to have lots of surgery until you feel better. Diagnose your problem first. It might be something small like a network setting or it could be one bad line in your code.

Some tips for profiling:

How to Profile Your Rails Application

Performance Testing Rails Applications

At the Forge - Profiling Rails Applications

Once you have found the bottleneck you can figure out what to do.

I recommend these videos: Railslab Scaling Rails

Revised now based on prof results:

OK. Now that you can see that your problem is that you are doing some sort of calculation using a query based on looping through the results of another active record query I'd advise you to look into building a custom SQL statement combining your initial selection criteria and the loop calculation to get what you need. You can definitely speed this up by optimizing the SQL.

查看更多
相关推荐>>
4楼-- · 2019-03-09 06:09

There are some good screen casts on this topic http://railslab.newrelic.com/scaling-rails

Things like fragmet caching and using :include (to avoid n+1) can help. It sounds like you're already using memcached, so why not curl the url to prefetch the cache?

查看更多
冷血范
5楼-- · 2019-03-09 06:10

Execution times this long would make me suspect a network issue - maybe a DNS query is timing out on a primary DNS server?

查看更多
Lonely孤独者°
6楼-- · 2019-03-09 06:12

When I bound the server to the boxes ip address instead of 0.0.0.0, this sped things up for me.

查看更多
登录 后发表回答