Pinned post
@Hibernate JOIN FETCH may not save you!
I ran a N+1 detector AI over Shopizer, Finreact, and PetClinic. Most fixes seemed obvious. The obvious ones didn't work.
Then pointed it at ExoBench sandbox and the fun began!
exobench.ai/blog/join-fetc…
1. A JOIN FETCH in a second query heals nothing you already hold. EclipseLink will not attach those collections onto entities already in memory. The N+1 stayed at 12.
2. Fetching the lazy parent collection? Removes exactly one level. The EAGER grandchildren keep firing. Still 25 statements.
3. setMaxResults next to a collection join fetch silently drops your LIMIT. Hibernate loaded 18 entities to serve a page of 2, and does the same thing on 5.6 and 6.6.
4. default_batch_fetch_size divides your N+1, it does not remove it. 12 statements became 3, and it still fetched the collection the page never renders.
5. findById twice in one request? Two full queries. Same id, no session spanning the two calls, nothing cached.
Every one of those looked correct in the source. Three of them were the fix.
A metadata analyzer would have approved all five. You only find this out by running the mapping and counting the SQL, and ExoBench will do this for you with no build, no runtime, no JVM agent, no test annotations!
Looking for 20 people with a real JPA codebase and a coding agent to try and break it. Reply or DM and I'll send access.
I ran a N+1 detector AI over Shopizer, Finreact, and PetClinic. Most fixes seemed obvious. The obvious ones didn't work.
Then pointed it at ExoBench sandbox and the fun began!
exobench.ai/blog/join-fetc…
1. A JOIN FETCH in a second query heals nothing you already hold. EclipseLink will not attach those collections onto entities already in memory. The N+1 stayed at 12.
2. Fetching the lazy parent collection? Removes exactly one level. The EAGER grandchildren keep firing. Still 25 statements.
3. setMaxResults next to a collection join fetch silently drops your LIMIT. Hibernate loaded 18 entities to serve a page of 2, and does the same thing on 5.6 and 6.6.
4. default_batch_fetch_size divides your N+1, it does not remove it. 12 statements became 3, and it still fetched the collection the page never renders.
5. findById twice in one request? Two full queries. Same id, no session spanning the two calls, nothing cached.
Every one of those looked correct in the source. Three of them were the fix.
A metadata analyzer would have approved all five. You only find this out by running the mapping and counting the SQL, and ExoBench will do this for you with no build, no runtime, no JVM agent, no test annotations!
Looking for 20 people with a real JPA codebase and a coding agent to try and break it. Reply or DM and I'll send access.