5 Ways to Speed Up Your Rails App
2009-10-30 16:43
441 查看
Ruby is a fast language, and a great one in so many ways, but
nothing in this world is truly free. It’s very easy to do things that
seem inconsequential but that later can bring your application to a
grinding halt. In this post, I’ll outline five important ways that you
can avoid some of the most common problems Rails apps encounter.
Before continuing, a disclaimer: do not take these tips and refactor your code ad-hoc. Take
everything with a grain of salt and perform your own measurements to
determine which pieces of your app are slow. Before making any
performance optimizations, get set up with a profiling tool, like
RubyProf, New Relic, Scout, etc. You always want to know where the most
significant bottlenecks are for you, and focus your efforts there first.
has been the lack of eager loaded associations. A simple extra
when performing ActiveRecord finds will prevent 1+N queries. So for
example, if you are displaying a list of articles on your blog homepage
and want to display the author’s name as well, load the posts with
For those complex pages, eager loading works multiple levels deep.
Newer versions of ActiveRecord handle complex eager loading cases much
more elegantly by splitting up a large join query into multiple smaller
queries that make better sense.
Note: only perform the eager load when you actually plan to use the objects, because there’s fairly significant overhead to creating many ActiveRecord objects.
it makes sense. Relational databases are designed to query large
amounts of data and return results; Ruby is not.
For example, if you want to check if the user currently logged in
has commented on an article, you don’t need to load all the comments
for that article. Iterate through each one, and check whether at least
one comment was created by the current user. Doing this will
instantiate objects for every single comment and then instantly discard
them after the check is done. A much better way to obtain the same
result is to push the logic to the database by doing a SELECT COUNT
statement. ActiveRecord has an easy way to do this:
as quickly as possible, so only do the bare minimum needed to return
the response and defer everything else. Actually sending out an email
is relatively slow and users don’t generally care if emails are sent
during the request cycle or right after.
Whether this is implemented using a simple Ruby thread or a robust,
distributed queuing system like RabbitMQ doesn’t really matter. Rails 3
will ship with a default queuing system, but until then, I suggest
checking out DelayedJob and BackgroundJob.
use existing plugins and gems instead of recreating the work in house.
This usually introduces a significant amount of new code to the
application that is relatively unknown.
There are many great Rails plugins out there. But before depending
on a new gem or plugin, I suggest at least skimming the source — check
for any craziness. Also be sure you’re using plugins for their intended
purposes — or things are likely to go awry.
running your code and start cleaning up unused objects. This process
can take between 100 and 400ms on MRI (JRuby has a better behaved,
tunable garbage collector through the JVM), which is a noticeable
period of time. Avoid this as much as possible. This means avoid creating unnecessary objects. I have already mentioned a couple of ways to do this in the previous tips.
In general, the best way to avoid the unnecessary creation of
objects is to understand how Ruby and the libraries in use work. For
example, understand the difference between these two snippets:
The first snippet creates a new Array object and a new String object
for each element in the Array. The second snippet just mutates the
String objects in the Array without creating new Ruby objects.
Granted, this tip only makes a significant difference when dealing
with large data structures, but it’s a good idea to keep in the back of
your mind whether or not you actually need to duplicate objects. If you
have arrays containing thousands of ActiveRecord objects and use
There are many other aspects of a Ruby on Rails application that can
cause bottlenecks; listing them all is obviously impossible. That said,
the most important thing to learn is how to locate these bottlenecks.
Solving them can be handled on a case by case basis.
nothing in this world is truly free. It’s very easy to do things that
seem inconsequential but that later can bring your application to a
grinding halt. In this post, I’ll outline five important ways that you
can avoid some of the most common problems Rails apps encounter.
Before continuing, a disclaimer: do not take these tips and refactor your code ad-hoc. Take
everything with a grain of salt and perform your own measurements to
determine which pieces of your app are slow. Before making any
performance optimizations, get set up with a profiling tool, like
RubyProf, New Relic, Scout, etc. You always want to know where the most
significant bottlenecks are for you, and focus your efforts there first.
Eager Load Associations
The most common and significant problem that I’ve seen in Rails appshas been the lack of eager loaded associations. A simple extra
_:include_
when performing ActiveRecord finds will prevent 1+N queries. So for
example, if you are displaying a list of articles on your blog homepage
and want to display the author’s name as well, load the posts with
Post.all(:include => :author).
For those complex pages, eager loading works multiple levels deep.
Newer versions of ActiveRecord handle complex eager loading cases much
more elegantly by splitting up a large join query into multiple smaller
queries that make better sense.
Note: only perform the eager load when you actually plan to use the objects, because there’s fairly significant overhead to creating many ActiveRecord objects.
Do Database Work In the Database
In the same vein as the first tip, try leveraging the database whenit makes sense. Relational databases are designed to query large
amounts of data and return results; Ruby is not.
For example, if you want to check if the user currently logged in
has commented on an article, you don’t need to load all the comments
for that article. Iterate through each one, and check whether at least
one comment was created by the current user. Doing this will
instantiate objects for every single comment and then instantly discard
them after the check is done. A much better way to obtain the same
result is to push the logic to the database by doing a SELECT COUNT
statement. ActiveRecord has an easy way to do this:
Article.comments.count(:conditions => ["user_id = ?", current_user.id]) > 0
Do as Little as Possible During the HTTP Request Cycle
You want to be able to return a response to the end user’s requestas quickly as possible, so only do the bare minimum needed to return
the response and defer everything else. Actually sending out an email
is relatively slow and users don’t generally care if emails are sent
during the request cycle or right after.
Whether this is implemented using a simple Ruby thread or a robust,
distributed queuing system like RabbitMQ doesn’t really matter. Rails 3
will ship with a default queuing system, but until then, I suggest
checking out DelayedJob and BackgroundJob.
Know Your Gems and Plugins
As Rails applications get more complicated, a good thing to do is touse existing plugins and gems instead of recreating the work in house.
This usually introduces a significant amount of new code to the
application that is relatively unknown.
There are many great Rails plugins out there. But before depending
on a new gem or plugin, I suggest at least skimming the source — check
for any craziness. Also be sure you’re using plugins for their intended
purposes — or things are likely to go awry.
Avoid Creating Unnecessary Objects
Every time Ruby’s garbage collector is triggered, Ruby will stoprunning your code and start cleaning up unused objects. This process
can take between 100 and 400ms on MRI (JRuby has a better behaved,
tunable garbage collector through the JVM), which is a noticeable
period of time. Avoid this as much as possible. This means avoid creating unnecessary objects. I have already mentioned a couple of ways to do this in the previous tips.
In general, the best way to avoid the unnecessary creation of
objects is to understand how Ruby and the libraries in use work. For
example, understand the difference between these two snippets:
sentences.map { |s| s.strip } sentences.each { |s| s.strip! }
The first snippet creates a new Array object and a new String object
for each element in the Array. The second snippet just mutates the
String objects in the Array without creating new Ruby objects.
Granted, this tip only makes a significant difference when dealing
with large data structures, but it’s a good idea to keep in the back of
your mind whether or not you actually need to duplicate objects. If you
have arrays containing thousands of ActiveRecord objects and use
rejectvs.
reject!, you’ve just created a second array which could potentially have thousands of objects.
There are many other aspects of a Ruby on Rails application that can
cause bottlenecks; listing them all is obviously impossible. That said,
the most important thing to learn is how to locate these bottlenecks.
Solving them can be handled on a case by case basis.
相关文章推荐
- Ten ways to speed up the download time of your web pages
- Permanent Link: 101 ways to speed up your Magento e-commerce website
- UX Tuneup: 5 Ways to Improve Your iOS App
- Ten ways to speed up the download time of your web pages
- [HTML/CSS] Ten ways to speed up the download time of your web pages - Trenton Moss
- [AngularJS] 5 simple ways to speed up your AngularJS application
- 每日英语:Upgrade Your Life: How to speed up your PC (or Mac)
- 25 Creative Ways to Promote Your App for Free
- Five Ways to Rev up Your SQL Performance
- iOS真机调试-Your maximum App ID limit has been reached. You may create up to 10 App IDs every 7 days
- iOS开发中,真机调试-Your maximum App ID limit has been reached. You may create up to 10 App IDs every 7 da
- Five Ways to Rev up Your SQL Performance
- 50 Tools to Speed Up Your PC
- Warbler, A Little Birdie To Introduce Your Rails App To Java
- Build your own ObjectPool in Java to boost app speed
- Learning Flex 3: Getting up to Speed with Rich Internet Applications
- facebook permissions : How to check if the user has already allowed publish_stream for your app
- 17 ways to obtain your latest Vulnerabilities/Advisories/Exploits elsewhere
- Eight Ways Your Android App Can Leak Memory
- Speed Up Your Site: Web Site Optimization