Spring JPA: when to use “Join Fetch”

Avoid N+1 Queries and retain the retrieval logic

Dev INTJ Code
Javarevisited
3 min readSep 28, 2020

--

Photo by Sam Pak on Unsplash

One of the first and most common problems encountered by developers who are new to JPA / Hibernate is n+1 queries. It’s because the code that is usually responsible for n+1 queries doesn’t look weird but looks so simple. It makes other developers unaware of the performance issue and only discovers it upon having enough data/records to the database.

It might look something as simple as this: person.getAddresses();

For this article, I’ll be discussing a simple yet common scenario wherein using “Join Fetch” would be beneficial. I’ll also include two integration tests to compare the performance. But first, let’s read the definition from the documentation.

Hibernate Documentation

“A “fetch” join allows associations or collections of values to be initialized along with their parent objects using a single select. This is particularly useful in the case of a collection.”

Here’s a simple scenario to demonstrate the above definition:

Domain Entities / Models:

A Person Entity has a collection of Addresses

Now that we have our domains ready, create a PersonRepository and then, query all records from Person entity and simply display each address line. Let’s start with the wrong approach which will lead to n+1 queries.

N+1 Queries Results

Below is an integration test that demonstrates a code that leads to n+1 queries.

With the gist of the integration test, I intentionally removed the imports and other annotations — so we can focus on the important parts.

Results from running the integration test above:

121515718 nanoseconds spent executing 51 JDBC statements;

Retrieved 50 records, executed 51 queries, and took about 121 ms

This might look negligible because we only have 50 records, but this clearly demonstrated the n+1 queries scenario. Let’s now try using “Join Fetch” while preserving this way of displaying all address lines and compare the results using the same records.

JOIN FETCH Results

Below is the code for the PersonRepository having a retrieveAll method that utilizes JPQL to use “Join Fetch”.

The integration test would be almost similar from the previous one, the only difference is now we are using the retrieveAll method that we just created.

With the gist of the integration test, I intentionally removed the imports and other annotations — so we can focus on the important parts.

Results from running the integration test above:

15411157 nanoseconds spent executing 1 JDBC statements

Retrieved 50 records, executed 1 query, and took about 15 ms

Conclusion

N+1 Queries: executed 51 queries, and took about 121 ms
JOIN FETCH: executed1 query, and took about 15 ms

The above comparison while may vary and limited to 50 records has a huge gap in performance and would probably have an exponential difference directly proportional to the number of records.

Using Join Fetch is one way to solve n+1 queries, while retaining the retrieval logic. Given that, there are other approaches e.g. Projections, and so on.

The full source code for this article is available on Github.

I hope you’ve enjoyed reading the article.

Happy Coding!

--

--

Javarevisited
Javarevisited

Published in Javarevisited

A humble place to learn Java and Programming better.

Dev INTJ Code
Dev INTJ Code

Written by Dev INTJ Code

Senior Software Engineer specializing in Backend Development, particularly in Java, utilizing the tech within the Spring Framework ecosystem;