front and back-end web development, Leeds, UK


Richard's Blog - Design, coding and life in Japan

Richard

Using :include in Rails ActiveRecord call doesnt create a joins query

I am currently writing an Rails app that uses quite a few database calls. I wanted to cut these calls down so I knew I would need to use the :include option in ActiveRecord. I was expecting from what Ryan Bates mentioned in one of his RailsCasts that a nice join would be created for me in one query.

I used the following code

@page=Page.published.top_level.website(@website.id).ordered.first(
        :include=>[{:page_contents=>:attachment}, :tags, :children]
)  

I ended up getting the following

  Page Load (1.0ms)   SELECT * FROM `pages` WHERE (`pages`.`id` = 80) 
  Page Load (0.4ms)   SELECT `pages`.* FROM `pages` WHERE (`pages`.parent_id = 80) ORDER BY position
  PageContent Load (2.3ms)   SELECT `page_contents`.* FROM `page_contents` WHERE (`page_contents`.page_id = 80) ORDER BY position
  PageContent Columns (1.8ms)   SHOW FIELDS FROM `page_contents`
  Attachment Columns (1.5ms)   SHOW FIELDS FROM `attachments`
  Attachment Load (0.3ms)   SELECT * FROM `attachments` WHERE (`attachments`.`id` IN (876,1181)) 
  PageTag Load (0.3ms)   SELECT `page_tags`.* FROM `page_tags` WHERE (`page_tags`.page_id = 80) 

What happened to my nice single query?

Well it seems and I have also thought this once before myself, that Rails breaks down queries for performance, what I hear you say? When you call large chained joins (especially with right joins) you end up getting data doubled up here there and everywhere. Rails does a nice job of breaking the calls down efficiently. It does however use joins when you have a condition in the association. There may be times when these calls hitting the database end up being too much, in which case a custom query may be needed.

In my case I will be caching most of this stuff anyway, but it was interesting to look into. I also found a good explanation here - even if a little dated.

Tags:

Recent Blog Posts