Django: Solve N + 1 query with Eager Loading

Tram Ho

Today I will introduce to everyone about Eager Loading in Django. Surely anyone from other languages ​​like Ruby or PHP switched to Python are too familiar with this keyword, right? But not everyone knows about it and I will join you to find out what Eager Loading in Django will be like. Let’s go!

What is Eager Loading?

Eager Loading is a concept that while accessing data, you will get the necessary data along with objects (objects) related to that data. It is the opposite of Lazy Loading when you only receive one data in a query and have to execute the query again when you want to retrieve objects related to it.

Talking about here is a bit confusing, right =)) because I also find it a bit confusing. But okay, let’s once again understand it through the following example:

As can be easily seen in the above example we had to perform: 1 query to retrieve all cars and for each car it would be a query to get its brand name. If we have 10 cars, this loop will have to perform 11 queries.

In other words, we had to perform N + 1 queries. What if we have a few thousand, or even a few million cars? That’s a huge number …

But with Eager Loading , this problem is easily solved.

Solve the problem

For this problem, I will introduce to you 2 ways to solve it. Before learning what these two ways are, let’s try to run the following code:

If we look at it, we can see that these 2 ways are not different and similar to the original writing style, right? But after running, let’s see what the number of queries that these two codes performed is

At this point, we have realized the difference between the two ways and compared with the original writing, right. Through the above code, I want to introduce to you two ways of handling that is to use select_related and prefetch_related .

According to Django’s doc it is clear:

  • select_related follow foreign key relationships, select objects related to it when querying by JOIN them.
  • prefetch_related does separate searches for each relationship and does * joining in python .

Sorry guys because I have to mark an asterisk (*) before the phrase joining in python . Because I do not know how to describe it correctly the message of this phrase.

Both select_related and prefetch_related were designed to reduce the number of queries, but they are implemented in different ways.

select_related works by creating a query join and including the fields of the relevant object in the SELECT statement . Also for this reason, select_related only takes one query that can receive all objects involved. However, there are a few select_related when you use select_related because it only takes 1 query that can retrieve all the related objects, so to avoid having too many large result sets from many joins. In a relationship, select_related is recommended in one-to-many, or one-to-one relationships.

prefetch_related , on the other hand, executes the queries separately for each relationship, and concatenates them. This allows it to pre-search and pre-filter objects in a many-to-many relationship using the WHERE IN clause , which is not possible by select_related .

The above is my share in solving the problem of N + 1 queries. Hope you guys continue to support me in the next articles.

Related links:

https://docs.djangoproject.com/en/3.0/ref/models/querysets/#select-related

https://stackoverflow.com/a/45377282

Share the news now

Source : Viblo