12 minutes / published

The N+1 Problem, Caused on Purpose - and When the Fixes Are Wrong

A deliberately broken query, three fixes, the pagination trap, and a geo query with stable ordering.

Break It So The Logs Have A Shape

N+1 is easiest to learn when a test creates it deliberately. The broken showtime path loads rows first, then touches lazy movie and screen associations.

Once the extra selects are visible, JOIN FETCH, EntityGraph, and DTO projection become tradeoffs instead of cargo-cult fixes.

Three Fixes, Three Costs

JOIN FETCH is direct and readable for one bounded graph. EntityGraph keeps the repository method shape cleaner. DTO projection skips entity loading when the API needs a read model.

The course keeps query-count assertions loose because exact counts can drift with metadata queries. The lesson is the order of magnitude and the access path.

Fetch Join Pagination Can Lie

A fetch join over a parent collection can duplicate parent rows or force in-memory pagination. That is not a theoretical edge case; it is one of the fastest ways to ship a slow page that passed review.

The course answer is DTO projection or two-step page IDs followed by a detail fetch.

Geo Query Needs Stable Ordering

The native query starts with a bounding-box prefilter, then orders by distance, start time, and ID.

Distance alone is not enough for stable pagination. A backend API has to make ties deterministic.