Preload Active Record Associations in Rails Application
Active Record makes database querying so simple. Chain together a few methods and bam, you’ve saved your self lines and lines of T-SQL. The problem is this simplicity masks the underlying operation and it’s very easy to not realize how inefficient your database calls are.
UserLoad(1.1ms)SELECT`users`.*FROM`users`WHERE'id'=1LIMIT1PostLoad(0.7ms)SELECT`posts`.*FROM`blogs`WHERE`blogs`.`user_id` = 2 Comment Load (0.7ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 43 Comment Load (1.7ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 55 Comment Load (2.2ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 32 Comment Load (0.9ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 66 Comment Load (2.2ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 56 Comment Load (4.8ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 65 Comment Load (1.8ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 68 Comment Load (0.8ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 71
The user has commented in 9 different posts, which results in 9 separate queries to the DB. This is a small scale example, but you can see how this can compound into something nasty.
he solution is to user includes method:
1
@user=User.find(id).includes(:posts=>:comments)
When using includes method, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries. The actual query executed is converted into a more optimal singular query and it is that result set that is iterated over instead of the replicated find(id) style queries.
Our query stack list now looks like:
123
UserLoad(1.0ms)SELECT`users`.*FROM`users`WHERE'id'=1LIMIT1PostLoad(0.4ms)SELECT`posts`.*FROM`posts`WHERE`posts`.`user_id` IN (1)Comment Load (0.5ms) SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` IN (43, 55, 32, 66, 56, 65, 68, 71)