Rails: Joins, Preload, Eager load and Includes

More, Better, Faster!

Rails: Joins, Preload, Eager load and Includes

Ruby on rails active record

 

In Rails, the most common methods used to fetch association data are joins, preload, eager_load, and Includes. We will discuss all of them in this blog.

1: Joins

It applies inner joins among the associations (without loading association data) and should match with at least one of the associated records and because of it duplicate records can be returned. It is used if we don’t want to access associations and only filter out records on the basis of it as they are not loaded into memory and will result in N+1 queries if accessed. Example:

 

Chapter.joins(:pages)

 

SELECT “chapters”.* FROM “chapters” INNER JOIN “pages” ON “pages”.”chapter_id” = “chapters”.”id”

 

2: Preload

It results in a separate query to load association data (one query per association). It is used if we want to access the associations, as they will be loaded in memory, without applying any filters on them as where clause is not supported on the associations and will result in an error though it can be applied on the parent association itself. Example:

 

Chapter.preload(:pages)

 

 SELECT  “chapters”.* FROM “chapters”

SELECT “pages”.* FROM “pages” WHERE “pages”.”chapter_id” IN (1)

 

3: Eager load

It results in a left outer join so all the associations are loaded in a single query. It is used only if we want to access the associations, as they will be loaded in memory, and also want to filter out records on the basis of associations as where clause is supported or wants all the associations to be fetched in a single query. Example:

 

Chapter.eager_load(:pages)

 

SELECT “chapters”.”id” AS t0_r0, “pages”.”id” AS t1_r0 FROM “chapters” LEFT OUTER JOIN “pages” ON “pages”.”chapter_id” = “chapters”.”id” AND “chapters”.”id” IN (1)

 

4: Includes

Its default behavior is of preload but unlike Preload, we can apply where clause on associations which then changes its behavior to eager_load or in case we want this as a default behavior we can use references. Example:

 

Chapter.includes(:pages)

 

SELECT  “chapters”.* FROM “chapters”

SELECT “pages”.* FROM “pages” WHERE “pages”.”chapter_id” IN 1)

 

In the above example, we can see there were two separate queries to fetch chapter and pages data.

 

Chapter.includes(:pages).references(:pages)

 

SELECT “chapters”.”id” AS t0_r0, “pages”.”id” AS t1_r0 FROM “chapters” LEFT OUTER JOIN “pages” ON “pages”.”chapter_id” = “chapters”.”id” WHERE “chapters”.”id” IN (1)

 

In the above example, we can see a single query fetches data for both chapters and pages.

 

Conclusion

Most of the time we will be using joins and includes but it is good to have the knowledge of preload and eager_load so we can optimize the queries according to the situation.

No Comments

Add your comment