liveBook · Manning

N + 1 query problem

As explained in Java Persistence with Spring Data and Hibernate epub

The n+1 selects problem is a data-access performance anti-pattern in which one query retrieves a root object and an additional query retrieves each associated object or collection element.

The N + 1 query problem is a data-access performance anti-pattern caused by navigating lazily loaded object associations one element at a time. One query loads the root objects, then an additional query loads each associated object or collection. For n associated records, the operation executes one query plus n more. section 1.2.5 section 12.2.1

Loading sellers for items

A JPQL query loads a list of Item entities with one SQL SELECT. Iterating over the items and calling item.getSeller().getUsername() triggers another SELECT for each seller. A lazily loaded bids collection produces the same pattern: checking item.getBids().size() loads each collection separately; 100 bids can therefore require 101 SQL queries. section 12.2.1

Path: Ch12/nplusoneselects/src/test/java/com/manning/javapersistence/ch12
 /nplusoneselects/NPlusOneSelects.java
 
List<Item> items =
           em.createQuery("select i from Item i").getResultList();
// select * from ITEM
for (Item item : items) {
    assertNotNull(item.getSeller().getUsername());     #1
    // select * from USERS where ID = ?
}
#1 Whenever we access a seller, each of them must be loaded with an additional <kbd>SELECT</kbd>.

Inspect the complete seller example showing the root Item query, the loop, and the additional user SELECT. section 12.2.1

Choose a fetching strategy according to the procedure that will use the data:

  • Keep associations lazy by default when appropriate, but recognize that on-demand navigation can generate too many small SQL statements. section 12.2
  • Avoid replacing every lazy association with eager loading: larger queries may reduce statement count while creating oversized Cartesian-product result sets. section 1.2.5 section 12.2.1
  • Define global mapping defaults, then override them for particular procedures with a custom JPQL query, CriteriaQuery, or SQL query. section 12.2

How Java Persistence with Spring Data and Hibernate epub covers it

How deep it goes
Demonstrates the query count with Java loops and SQL, then compares lazy, eager, and procedure-specific fetching strategies.
Examples
Uses User–BillingDetails navigation and Item seller and bids examples to expose per-association SELECT statements.
What it assumes
Assumes Java object associations, lazy loading, SQL SELECT statements, and basic ORM query usage.
What you can do after
Diagnose query amplification and choose a fetch plan or query override suited to the application procedure.
How it connects
Connects lazy loading, eager loading, fetch plans, fetch strategies, JPQL, CriteriaQuery, SQL, and the Cartesian product problem.

Also explained in

Compare how 4 books explain N + 1 query problem →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Java Persistence with Spring Data and Hibernate epub. The section links point to the parts of the book it draws on.