ActiveRecord is slow, how to make it your friend

I’m sure everyone in this audience has faced the following situation: experienced ruby on rails developers working with newbies in the same project, many features done, many landing pages, dynamic content, searches etc. We all remembered one of the best reasons developers prefer ruby and or ruby on rails, is elegant and is fun and easy to read. And you are absolutely right, except for the fact that small projects can become very slow and unresponsive when you combine a lot of experience with less knowledge of cost of using something like User.where(“all the criteria”).profile.tickets.reviews when you want to show all the available ratings a class or a product or a service has.

Experienced developers or not,we all need to know that even though active record syntax is glamorously beautiful to read, it is very very bad in terms of performance. Given the scenario described above, we shouldn’t be using more than 1 relationship to find something by using Active Record, how come?

Let me explain:

1. If you use User.find(1).profile you will automatically load all the columns from user and from profile and as we all know those tables it usually contain many fields that you might not need for such a case

2. If you try to do it with 3,4 or 5 tables you will have the same effect but magnified adding a query + 1 on each case

3. Your product owner will yell at you many times

Then what do we do?

First of all, don’t trust my words, go ahead and read your logs, install new relic if you don’t have it, just take a look at the thousands of unnecessary queries that the app does when having so many relationship to get the right data that will print the ratings in your app.

Once you’ve done that, think about the SQL query that you need to show those specific data for that page, and make these questions to yourself:

1. What columns do you need to show the info required? Choose them wisely Model.select() or pluck is your friend

2. Is there an math operation to be done in order to show the correct result? Find out if you can make it with using embeded SQL functions from whatever DB you use

3. Do you have to include an specific list of columns from another table concatenated or with an specific format? Use subqueries

4. Create your query in your favorite SQL editor, run it against your local first

5. Now generate the SQL with the correct parameters and forget using more than one relationship

This will reduce the time consumed by the query +1 generated each time when looping through results. Remember also, you don’t need to add “select *” to grab every single column in those tables. When in doubt remove all the columns and add one at a time until you get the correct result.

That’s it. Of course this apply to a few scenarios, you choose the best. Please tell me your thoughts!

JoseLuis Torres