Twitxy Saved

Alexander Ioffe

Verified account This account is verified. Learn more

@deusaquilus

Take control of your database with exoquery.com the only LINQ for Kotlin!
Joined October 2020
217 Following 1.8K Followers 3.2K Posts

Latest posts 5

Pinned post

Alexander Ioffe Verified account @deusaquilus
@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.
exobench.ai JOIN FETCH May Not Save You — Seven things JPA developers believe about N+1, checked against the... We ran a JPA N+1 detector over Shopizer, Apache Fineract, and Spring PetClinic, then used it to check the standard fixes. A second JOIN FETCH query left the N+1 at 12 statements. Fetching the parent...
Alexander Ioffe Verified account @deusaquilus
78 ms on the first run.
0.07 ms on the second.

Every page already in shared_buffers both times.
That's synchronize_seqscans: above a quarter of shared_buffers, each seq scan starts where the last one stopped.

One EXPLAIN ANALYZE is a sample size of one.

(1/2)
Alexander Ioffe Verified account @deusaquilus
Beautiful! The very definition of Kafkaesque reasoning!

Surely if you dare doubt that arbitrary group of people in an arbitrary country should be able to try you for being a war criminal then you must be a war criminal yourself!
Nathan J Robinson @NathanJRobinson Oct 9
if you think the International Criminal Court is a threat to you... you might just be a war criminal
View quoted post on X