1

I am getting bad performance after upgrading an application to Rails 3.

Before upgrading, I got 60ms - 100ms response times.

After upgrading, I get 300ms - 1500ms response times.

The log shows a sample response time from each time:

Rails 3.0.0: Completed 200 OK in 1454ms (Views: 1314.6ms | ActiveRecord: 25.1ms)
Rails 2.3.8: Completed in 31ms (View: 27, DB: 1) | 200 OK [FILTERED]

I've tried running using passenger and 'rails server' (both results are close). I've created two identical applications (running in 2.3.8 and 3.0.0) to demonstrate the performance differences. The code that appears to be causing the performance issues is:

<%- @posts.each do |post| -%>
  <h1><%= post.title %></h1>
  <p><%=truncate post.body %></p>
  <%- post.comments.each do |comment| -%>
    <h2><%= comment.title%></h2>
    <p><%=truncate comment.body %></p>
    <ul>
    <%- comment.ratings.each do |rating| -%>
      <li><%=truncate rating.notes %></li>
    <%- end -%>
    </ul>
  <%- end -%>
<%- end -%>

For full source, the projects are available here: http://github.com/ksylvest/performance

Thanks!

Kevin Sylvestre
  • 37,288
  • 33
  • 152
  • 232
  • 1
    if webrick and passenger are giving similar performance, you haven't set up passenger properly – Matt Briggs Jun 23 '10 at 00:39
  • @Matt Hmm, it is a relatively small application on a local machine (running Mac OS X). I followed the passenger setup guide given after installing the GEM. This is a clean Snow Leopard install, and I tried switching the Rack and Rails environments between development and production. Any other ideas? – Kevin Sylvestre Jun 23 '10 at 00:44

2 Answers2

1

Without much to go on, there's not much anyone can do.

generated source files

In Ruby?

Really?

nested loops

select n+1? Do you need to specify in certain queries that specific associations need to be eager-loaded?

--EDIT--

The ActiveRecord query API and performance characteristics have changed significantly from v2 to v3.

Perhaps you need to eager-load some associations?

To eager-load the comments with the posts, use

@posts = Post.includes(:comments)

and to eager-load the comments and the comments' ratings with the posts, use

@posts = Post.includes(:comments => :ratings)
yfeldblum
  • 65,165
  • 12
  • 129
  • 169
  • Hi Justice. Sorry it is difficult to be precise, but I am seeing a slow down application wide. The logs show that the ActiveRecord queries are approximately the same, but the view rendering times have gone up by 100 times. I'm just wondering if others have experienced similar issues. – Kevin Sylvestre Jun 23 '10 at 00:42
  • @Justice Hi Justice. Sorry I couldn't release any source for the original project, but I spent an hour generating sample projects that appear to have the same issue. The project is dead simple and just features basic nested looping. – Kevin Sylvestre Jun 23 '10 at 01:28
  • I added some hints about eager-loading. Do these hints help at all with your projects? – yfeldblum Jun 23 '10 at 02:31
  • Hi Justice. Thanks for the update. This cut down the runtime in both sample application I posted; I am currently using some eager loading in the private application, but I will be sure to check through to find any more improvements. However, my larger concern was moving from Rails 2.3.8 to Rails 3.0.0 and the five-ten slow down I experienced. Thanks for the great info though. Do you know if the lazy loading can be defaulted application wide? Thanks again! – Kevin Sylvestre Jun 23 '10 at 03:07
  • As an additional note. I pushed up a new version of the code so that others can see the performance improvements when using eager loading. The tests will now do benchmarks that I found useful in troubleshooting a few environment issues. Also, the eager loading seems to have a larger performance improvement (for me) in Rails 3.0.0 than in Rails 2.8.7. – Kevin Sylvestre Jun 23 '10 at 03:15
  • You can take a look at the `:has_many` method's `:include` options hash parameter: `Post.send :has_many, :categories, :include => :ratings`. – yfeldblum Jun 23 '10 at 03:42
  • @Justice Thanks! I'll take a look through it! – Kevin Sylvestre Jun 23 '10 at 17:43
1

Please include the version of Ruby you are using for your tests.

Try running Rails 3 on Ruby 1.9.2-head and see if you notice a difference. You can use something like RVM to try multiple versions of Ruby very easily.

As noted in this SO question, 1.9.1 seems to have some performance issues. If you are using Ruby Enterprise Edition with Rails 3, that may be causing some performance issues as well. If you use plugins that are not Ruby 1.9 compatible, make sure you are using REE >= 1.8.7-2010.02 as noted on the Edge Rails Guides.

I believe Rails 3 development is being targeted at 1.9.2 and backported to run on earlier versions.

Community
  • 1
  • 1
Awgy
  • 1,082
  • 11
  • 14
  • Thanks for the advice. ruby --version gives: ruby 1.8.7 (2009-06-12 patchlevel 174) [universal-darwin10.0] I am deploying to Heroku (currently only supports 1.8.7 and 1.9.1) and I am not sure about my plugin compatibility (will need some major time to test). I will check to see if the sample code has any performance changes with different ruby versions. – Kevin Sylvestre Jun 23 '10 at 01:54
  • 1
    @Kevin Sylvestre: Heroku does support the correct version of REE as noted in their latest blog post: http://blog.heroku.com/archives/2010/6/15/rails_3_beta_4_on_heroku/ You can check which stack you are running by typing `heroku stack` – Awgy Jun 23 '10 at 01:57
  • @Awgy Oops! Thanks you are right! I was using this as a guideline: http://docs.heroku.com/rails3. Looks like they have some out-of-date documentation. Thanks, I'll test it shortly. – Kevin Sylvestre Jun 23 '10 at 02:12
  • @Awgy I just finished figuring out RVM and running the tests! Using 1.9.2 reduced the response time to 20% of that when using 1.8.7 in the sample application. Now I just need to sort out some dependencies! Thanks for the help! That was exactly what I needed! – Kevin Sylvestre Jun 23 '10 at 02:33
  • @Kevin Sylvestre: I'm happy to hear that it helped =) – Awgy Jun 23 '10 at 03:08
  • @Awgy Just wondering how you managed to get the stack to 1.9.2 on Heroku? When I type heroku stack it only lists 1.8.6, 1.8.7 and 1.9.1. I read a bit more on the page and they mentioned that support will be available when it is officially released, so I am confused. Thanks. – Kevin Sylvestre Jun 23 '10 at 03:40
  • @Kevin Sylvestre: Heroku does not support 1.9.2 yet according to that blog post I linked. I use 1.9.2-head on a Slicehost VPS, which I find works very well price/performance wise compared to Heroku if you are up for the additional administration. – Awgy Jun 23 '10 at 05:12
  • @jpartogi You can try to run the benchmarks on your own to see. Just install RVM and download the source linked in the question. I found about four time performance improvements from upgrading Ruby and a two times improvement from adding eager loading. – Kevin Sylvestre Jun 23 '10 at 06:32
  • @Kevin: 4 time performance improvements is damn fast. I think I should try it. Thanks. – Joshua Partogi Jun 23 '10 at 07:31