{"id":81050,"date":"2026-09-02T11:09:08","date_gmt":"2026-09-02T05:39:08","guid":{"rendered":"https:\/\/2thenew.xyz\/blog\/?p=81050"},"modified":"2026-09-09T10:42:09","modified_gmt":"2026-09-09T05:12:09","slug":"hibernate-n1-query-problem-causes-solutions-and-production-best-practices","status":"publish","type":"post","link":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/","title":{"rendered":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices"},"content":{"rendered":"<h1>Introduction<\/h1>\n<p>A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to <strong>&#8220;Return all customers with their orders.&#8221;<\/strong> The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes:<\/p>\n<ol>\n<li><strong>Database CPU spikes<\/strong><\/li>\n<li><strong>Connection pool exhaustion<\/strong><\/li>\n<li><strong>Higher API latency<\/strong><\/li>\n<li><strong>Increasing infrastructure cost<\/strong><\/li>\n<\/ol>\n<p>A request that should run a few queries may silently run hundreds or thousands.<\/p>\n<p>Returning 1,000 customers with orders can mean:<\/p>\n<p><strong>1 customer query + 1,000 order queries = 1,001 SQL statements<\/strong><\/p>\n<p>Locally, with 10 customers, nobody notices.<\/p>\n<p>In production,<strong> round-trip cost dominates.<\/strong><\/p>\n<div id=\"attachment_81135\" style=\"width: 664px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81135\" class=\" wp-image-81135\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-39-42-1024x432.png\" alt=\"N+1 query explosion\" width=\"654\" height=\"275\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-39-42-1024x432.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-39-42-300x126.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-39-42-768x324.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-39-42-624x263.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-39-42.png 1499w\" sizes=\"auto, (max-width: 654px) 100vw, 654px\" \/><p id=\"caption-attachment-81135\" class=\"wp-caption-text\">N+1 query explosion<\/p><\/div>\n<p>Hibernate is usually not doing something wrong. Hibernate is following:<\/p>\n<ol>\n<li>Entity relationships<\/li>\n<li>Lazy loading rules<\/li>\n<li>Object navigation patterns<\/li>\n<\/ol>\n<p>The actual problem is a mismatch between <strong>Object-oriented programming access patterns<\/strong> and <strong>Efficient database access patterns<\/strong><\/p>\n<h1>What Is the N+1 Query Problem?<\/h1>\n<p>The N+1 query problem occurs when:<\/p>\n<ol>\n<li>One query loads the parent records.<\/li>\n<li>Additional queries load related records for each parent.<\/li>\n<\/ol>\n<p>The formula is: 1 Parent Query + N Child Queries = N+1 Queries<\/p>\n<div id=\"attachment_81118\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81118\" class=\"wp-image-81118 size-large\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-11-12-1024x572.png\" alt=\"Customer and Order Relationship\" width=\"625\" height=\"349\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-11-12-1024x572.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-11-12-300x168.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-11-12-768x429.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-11-12-624x349.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-11-12.png 1246w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81118\" class=\"wp-caption-text\">Customer and Order Relationship<\/p><\/div>\n<h1>Expected Efficient SQL Approach<\/h1>\n<div id=\"attachment_81120\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81120\" class=\"wp-image-81120 size-large\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-15-36-1024x652.png\" alt=\"Intended one-query shape for customers with orders\" width=\"625\" height=\"398\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-15-36-1024x652.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-15-36-300x191.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-15-36-768x489.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-15-36-624x397.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-15-36.png 1446w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81120\" class=\"wp-caption-text\">Intended one-query shape for customers with orders<\/p><\/div>\n<h1>Lazy loading often produces chatty SQL instead<\/h1>\n<div id=\"attachment_81121\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81121\" class=\"wp-image-81121 size-large\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-24-58-1024x701.png\" alt=\"Lazy Loading SQL Pattern\" width=\"625\" height=\"428\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-24-58-1024x701.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-24-58-300x205.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-24-58-768x526.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-24-58-624x427.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-24-58.png 1449w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81121\" class=\"wp-caption-text\">Lazy Loading SQL Pattern<\/p><\/div>\n<h1>Query Growth Example<\/h1>\n<p>Customers \u2192 SQL Queries<\/p>\n<p>10 \u2192 11 queries<br \/>\n100 \u2192 101 queries<br \/>\n1,000 \u2192 1,001 queries<br \/>\n10,000 \u2192 10,001 queries<\/p>\n<p>The problem is not only the number of rows.The real problem is:<\/p>\n<ol>\n<li><strong>Database network round trips<\/strong><\/li>\n<li><strong>Connection pool occupation<\/strong><\/li>\n<li><strong>Database CPU usage<\/strong><\/li>\n<li><strong>Increased request latency<\/strong><\/li>\n<\/ol>\n<p>Even simple queries become expensive when executed repeatedly.<\/p>\n<h1>Hibernate Example<\/h1>\n<p>Consider a typical Customer and Order relationship. A customer contains multiple orders.<\/p>\n<div id=\"attachment_81127\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81127\" class=\"wp-image-81127 size-large\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-54-40-1024x701.png\" alt=\"Customer Entity Mapping Diagram\" width=\"625\" height=\"428\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-54-40-1024x701.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-54-40-300x205.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-54-40-768x526.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-54-40-624x427.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-54-40.png 1449w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81127\" class=\"wp-caption-text\">Customer Entity Mapping Diagram<\/p><\/div>\n<h1><\/h1>\n<p>The orders are not loaded immediately. Hibernate waits until the application accesses:<\/p>\n<p>customer.getOrders();<\/p>\n<h1>ManyToOne Lazy Configuration<\/h1>\n<p>JPA defaults: @ManyToOne to FetchType.EAGER<br \/>\nThis default is often unsuitable for production systems.<\/p>\n<div id=\"attachment_81128\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81128\" class=\"wp-image-81128 size-large\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-57-41-1024x666.png\" alt=\"Order Entity Code Screenshot\" width=\"625\" height=\"406\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-57-41-1024x666.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-57-41-300x195.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-57-41-768x500.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-57-41-624x406.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-13-57-41.png 1492w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81128\" class=\"wp-caption-text\">Order Entity Code Screenshot<\/p><\/div>\n<h1>N+1 Query Example<\/h1>\n<p>Hibernate may look like object navigation in Java, but every lazy collection access can trigger another SQL query.<\/p>\n<div id=\"attachment_81133\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81133\" class=\"size-large wp-image-81133\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-24-12-1024x666.png\" alt=\"N+1 Loop Execution Diagram\" width=\"625\" height=\"406\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-24-12-1024x666.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-24-12-300x195.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-24-12-768x500.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-24-12-624x406.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-24-12.png 1492w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81133\" class=\"wp-caption-text\">N+1 Loop Execution Diagram<\/p><\/div>\n<h1>How Hibernate Creates N+1 Internally<\/h1>\n<p>With <strong>LAZY<\/strong>, Hibernate returns a <strong>proxy<\/strong> (many-to-one\/one-to-one) or a <strong>persistent collection wrapper<\/strong>.<\/p>\n<p>SQL runs on <strong>first access<\/strong> not when the parent entity is loaded.<\/p>\n<div id=\"attachment_81137\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81137\" class=\"wp-image-81137 size-large\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-15-56-1024x555.png\" alt=\"Lazy Proxy and Collection Wrappers \" width=\"625\" height=\"339\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-15-56-1024x555.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-15-56-300x163.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-15-56-768x416.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-15-56-624x338.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-15-56.png 1387w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81137\" class=\"wp-caption-text\">Lazy Proxy and Collection Wrappers<\/p><\/div>\n<div id=\"attachment_81138\" style=\"width: 630px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81138\" class=\" wp-image-81138\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-19-08-1024x900.png\" alt=\"&quot;Lazy Proxy and Collection Wrappers&quot; image.\" width=\"620\" height=\"546\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-19-08-1024x900.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-19-08-300x264.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-19-08-768x675.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-19-08-624x549.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-19-08.png 1028w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><p id=\"caption-attachment-81138\" class=\"wp-caption-text\">Lazy Proxy and Collection Wrappers<\/p><\/div>\n<p>&nbsp;<\/p>\n<div id=\"attachment_81139\" style=\"width: 644px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81139\" class=\" wp-image-81139\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-20-51-1024x592.png\" alt=\"Per-Customer Lazy Access in a Loop\" width=\"634\" height=\"366\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-20-51-1024x592.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-20-51-300x173.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-20-51-768x444.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-20-51-624x361.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-20-51.png 1526w\" sizes=\"auto, (max-width: 634px) 100vw, 634px\" \/><p id=\"caption-attachment-81139\" class=\"wp-caption-text\">Per-Customer Lazy Access in a Loop<\/p><\/div>\n<p>Common triggers include association access in loops, Jackson serialization while a session is open and OSIV.<\/p>\n<p>Many enterprise APIs disable OSIV (spring.jpa.open-in-view=false) and enforce explicit loading inside @Transactional services.<\/p>\n<p><strong>Session open<\/strong> \u2192 possible N+1 during serialization.<\/p>\n<p><strong>Session closed<\/strong> \u2192 often LazyInitializationException.<\/p>\n<h1>Why Does N+1 Happen?<\/h1>\n<p><strong>1. Lazy Loading Without a Fetch Plan<\/strong><\/p>\n<p>LAZY is usually the correct default. Blaming LAZY alone is inaccurate.<\/p>\n<p>A customer may own:<\/p>\n<ol>\n<li>Orders<\/li>\n<li>Payments<\/li>\n<li>Addresses<\/li>\n<li>Transactions<\/li>\n<\/ol>\n<p>The real bug is fetching data without a plan<\/p>\n<div id=\"attachment_81140\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81140\" class=\"size-large wp-image-81140\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-26-12-1024x649.png\" alt=\"Wide Customer Aggregate Graph\" width=\"625\" height=\"396\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-26-12-1024x649.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-26-12-300x190.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-26-12-768x486.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-26-12-624x395.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-26-12.png 1334w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81140\" class=\"wp-caption-text\">Wide Customer Aggregate Graph<\/p><\/div>\n<h1>2. Entity Relationships<\/h1>\n<p>Any association can introduce N+1:<\/p>\n<ol>\n<li>OneToMany<\/li>\n<li>ManyToOne<\/li>\n<li>ManyToMany<\/li>\n<\/ol>\n<p>ManyToMany can amplify cost because join-table access plus entity loads increase the number of SQL statements.<\/p>\n<div id=\"attachment_81146\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81146\" class=\"size-large wp-image-81146\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-31-47-1024x659.png\" alt=\"Relationship Patterns That Trigger N+1\" width=\"625\" height=\"402\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-31-47-1024x659.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-31-47-300x193.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-31-47-768x494.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-31-47-624x402.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-31-47.png 1507w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81146\" class=\"wp-caption-text\">Relationship Patterns That Trigger N+1<\/p><\/div>\n<h1>3. Returning Entities from REST APIs<\/h1>\n<p>Returning JPA entities from controllers is a frequent production mistake. The repository may look cheap while serialization walks lazy associations.<\/p>\n<div id=\"attachment_81153\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81153\" class=\"size-large wp-image-81153\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-34-02-1024x659.png\" alt=\"Entity Controller Anti-Pattern\" width=\"625\" height=\"402\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-34-02-1024x659.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-34-02-300x193.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-34-02-768x494.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-34-02-624x402.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-34-02.png 1507w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81153\" class=\"wp-caption-text\">Entity Controller Anti-Pattern<\/p><\/div>\n<div id=\"attachment_81156\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81156\" class=\"size-large wp-image-81156\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-35-17-1024x675.png\" alt=\"Jackson Serialization Triggering Lazy SQL\" width=\"625\" height=\"412\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-35-17-1024x675.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-35-17-300x198.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-35-17-768x506.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-35-17-624x411.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-15-35-17.png 1507w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81156\" class=\"wp-caption-text\">Jackson Serialization Triggering Lazy SQL<\/p><\/div>\n<div id=\"attachment_81176\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81176\" class=\"size-large wp-image-81176\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-08-44-1024x570.png\" alt=\"Entity-to-DTO API Boundary\" width=\"625\" height=\"348\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-08-44-1024x570.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-08-44-300x167.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-08-44-768x428.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-08-44-624x347.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-08-44.png 1320w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81176\" class=\"wp-caption-text\">Entity-to-DTO API Boundary<\/p><\/div>\n<p><strong>Repository cost is not API cost.<\/strong><\/p>\n<p>Entities model persistence.<\/p>\n<p>DTOs model contracts.<\/p>\n<h1>LAZY vs EAGER<\/h1>\n<p>Making everything EAGER usually creates another problem. EAGER does not reliably fix N+1 and does not guarantee one optimal SQL plan\u2014Hibernate may join or issue follow-up selects.<\/p>\n<p>It also over-fetches across unrelated use cases.<\/p>\n<p><strong>LAZY Loading<\/strong>:<br \/>\n\u2192 OneToMany<br \/>\n\u2192 ManyToMany<\/p>\n<p><strong>EAGER Loading<\/strong>:<br \/>\n\u2192 ManyToOne<br \/>\n\u2192 OneToOne<\/p>\n<div id=\"attachment_81178\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81178\" class=\"size-large wp-image-81178\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-15-40-1024x683.png\" alt=\"Explicit ManyToOne LAZY Declaration\" width=\"625\" height=\"417\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-15-40-1024x683.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-15-40-300x200.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-15-40-768x513.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-15-40-624x416.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-15-40.png 1509w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81178\" class=\"wp-caption-text\">Explicit ManyToOne LAZY Declaration<\/p><\/div>\n<p>Therefore explicitly declaring: @ManyToOne(fetch = FetchType.LAZY) is a common production practice.<\/p>\n<p><strong>Architectural rule:<\/strong> Mappings define relationships, use cases define fetch plans.<\/p>\n<h1>How To Detect N+1<\/h1>\n<p>Latency, CPU and memory alone are not enough.<\/p>\n<p>Ask: <strong>How many queries did a request execute?<\/strong><\/p>\n<p>Treat query count as a <strong>non-functional requirement<\/strong> for critical APIs similar to latency and throughput.<\/p>\n<div id=\"attachment_81179\" style=\"width: 1011px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81179\" class=\"size-full wp-image-81179\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-19-34.png\" alt=\"Spring Boot Hibernate SQL Logging Config\" width=\"1001\" height=\"652\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-19-34.png 1001w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-19-34-300x195.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-19-34-768x500.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-19-34-624x406.png 624w\" sizes=\"auto, (max-width: 1001px) 100vw, 1001px\" \/><p id=\"caption-attachment-81179\" class=\"wp-caption-text\">Spring Boot Hibernate SQL Logging Config<\/p><\/div>\n<div id=\"attachment_81180\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81180\" class=\"size-large wp-image-81180\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-21-01-1024x482.png\" alt=\"Repeated Orders SQL Indicating N+1\" width=\"625\" height=\"294\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-21-01-1024x482.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-21-01-300x141.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-21-01-768x361.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-21-01-624x294.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-21-01.png 1477w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81180\" class=\"wp-caption-text\">Repeated Orders SQL Indicating N+1<\/p><\/div>\n<p>Avoid permanent verbose SQL logging in production because of volume and overhead.<\/p>\n<div id=\"attachment_81181\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81181\" class=\"size-large wp-image-81181\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-23-23-1024x596.png\" alt=\"Enable Hibernate Statistics\" width=\"625\" height=\"364\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-23-23-1024x596.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-23-23-300x175.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-23-23-768x447.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-23-23-624x363.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-23-23.png 1506w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81181\" class=\"wp-caption-text\">Enable Hibernate Statistics<\/p><\/div>\n<div id=\"attachment_81182\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81182\" class=\"size-large wp-image-81182\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-26-31-1024x613.png\" alt=\"CI Query Budget Failure Example\" width=\"625\" height=\"374\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-26-31-1024x613.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-26-31-300x180.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-26-31-768x460.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-26-31-624x373.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-26-31.png 1457w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81182\" class=\"wp-caption-text\">CI Query Budget Failure Example<\/p><\/div>\n<div id=\"attachment_81183\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81183\" class=\"size-large wp-image-81183\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-28-00-1024x677.png\" alt=\"Request-to-Database Observability Flow\" width=\"625\" height=\"413\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-28-00-1024x677.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-28-00-300x198.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-28-00-768x507.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-28-00-624x412.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-16-28-00.png 1244w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81183\" class=\"wp-caption-text\">Request-to-Database Observability Flow<\/p><\/div>\n<p>Also index join FKs such as:<\/p>\n<p>orders.customer_id<br \/>\nHibernate cannot fix missing indexes.<\/p>\n<p>Use:<\/p>\n<ol>\n<li>p6spy<\/li>\n<li>datasource-proxy<\/li>\n<li>OpenTelemetry<\/li>\n<li>APM tools<\/li>\n<\/ol>\n<p>as appropriate and test with production-like cardinality.<\/p>\n<h1>Solutions<\/h1>\n<p>There is no universal fix. Choose based on:<\/p>\n<ol>\n<li>Data volume<\/li>\n<li>API requirements<\/li>\n<li>Transaction boundaries<\/li>\n<li>Read\/write patterns<\/li>\n<\/ol>\n<h1>1. JOIN FETCH<\/h1>\n<p>JOIN FETCH Repository Query \u2014 Demonstrates explicit fetch joining of orders with customers.<\/p>\n<div id=\"attachment_81295\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81295\" class=\"size-large wp-image-81295\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-25-24-1024x653.png\" alt=\"JOIN FETCH Repository Query\" width=\"625\" height=\"399\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-25-24-1024x653.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-25-24-300x191.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-25-24-768x490.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-25-24-624x398.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-25-24.png 1474w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81295\" class=\"wp-caption-text\">JOIN FETCH Repository Query<\/p><\/div>\n<div id=\"attachment_81296\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81296\" class=\"size-large wp-image-81296\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-27-50-1024x653.png\" alt=\"SQL Generated by JOIN FETCH\" width=\"625\" height=\"399\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-27-50-1024x653.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-27-50-300x191.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-27-50-768x490.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-27-50-624x398.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-27-50.png 1474w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81296\" class=\"wp-caption-text\">SQL Generated by JOIN FETCH<\/p><\/div>\n<p><strong>Use<\/strong> JOIN FETCH for:<\/p>\n<ol>\n<li>Bounded parent + one collection<\/li>\n<li>Cases where managed entities are required<\/li>\n<\/ol>\n<p><strong>Avoid<\/strong> when:<\/p>\n<ol>\n<li>Paginating joined collections<\/li>\n<li>Fetching multiple List bags<\/li>\n<\/ol>\n<div id=\"attachment_81297\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81297\" class=\"size-large wp-image-81297\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-30-20-1024x634.png\" alt=\"JOIN FETCH Pagination Mismatch\" width=\"625\" height=\"387\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-30-20-1024x634.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-30-20-300x186.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-30-20-768x476.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-30-20-624x386.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-30-20.png 1376w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81297\" class=\"wp-caption-text\">JOIN FETCH Pagination Mismatch<\/p><\/div>\n<p>SQL may return duplicate customer rows because of the join.<\/p>\n<p>Hibernate can remove duplicate entity references, but the database still processes the larger result set.<\/p>\n<p>Prefer <strong>DISTINCT<\/strong> for the result list and measure join-row volume.<\/p>\n<div id=\"attachment_81298\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81298\" class=\"size-large wp-image-81298\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-32-39-1024x660.png\" alt=\"Duplicate Parent Rows from Join\" width=\"625\" height=\"403\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-32-39-1024x660.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-32-39-300x193.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-32-39-768x495.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-32-39-624x402.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-32-39.png 1433w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81298\" class=\"wp-caption-text\">Duplicate Parent Rows from Join<\/p><\/div>\n<div id=\"attachment_81299\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81299\" class=\"size-large wp-image-81299\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-33-43-1024x660.png\" alt=\"Cartesian Product from Multiple Collection Joins\" width=\"625\" height=\"403\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-33-43-1024x660.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-33-43-300x193.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-33-43-768x495.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-33-43-624x402.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-33-43.png 1433w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81299\" class=\"wp-caption-text\">Cartesian Product from Multiple Collection Joins<\/p><\/div>\n<h1>2. EntityGraph<\/h1>\n<p>Spring Data EntityGraph Example \u2014 Shows repository-level fetch planning while mappings stay LAZY.<\/p>\n<div id=\"attachment_81300\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81300\" class=\"size-large wp-image-81300\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-35-37-1024x634.png\" alt=\"Spring Data EntityGraph Example\" width=\"625\" height=\"387\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-35-37-1024x634.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-35-37-300x186.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-35-37-768x476.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-35-37-624x387.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-35-37.png 1482w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81300\" class=\"wp-caption-text\">Spring Data EntityGraph Example<\/p><\/div>\n<p>Use EntityGraph for different repository graphs without duplicating JPQL.<\/p>\n<p>Prefer DTOs when:<\/p>\n<ol>\n<li>The API needs only a few columns<\/li>\n<li>The entity is wide<\/li>\n<\/ol>\n<h1>3. DTO Projection (Often Best for APIs)<\/h1>\n<p>Most list APIs do not need full entity graphs.<\/p>\n<div id=\"attachment_81301\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81301\" class=\"size-large wp-image-81301\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-38-47-1024x484.png\" alt=\"Minimal API JSON Response\" width=\"625\" height=\"295\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-38-47-1024x484.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-38-47-300x142.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-38-47-768x363.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-38-47-624x295.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-38-47.png 1479w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81301\" class=\"wp-caption-text\">Minimal API JSON Response<\/p><\/div>\n<div id=\"attachment_81302\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81302\" class=\"size-large wp-image-81302\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-40-06-1024x640.png\" alt=\"CustomerOrderDTO Definition\" width=\"625\" height=\"391\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-40-06-1024x640.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-40-06-300x188.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-40-06-768x480.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-40-06-624x390.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-40-06.png 1449w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81302\" class=\"wp-caption-text\">CustomerOrderDTO Definition<\/p><\/div>\n<div id=\"attachment_81303\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81303\" class=\"size-large wp-image-81303\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-41-07-1024x640.png\" alt=\"DTO Constructor Projection Query\" width=\"625\" height=\"391\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-41-07-1024x640.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-41-07-300x188.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-41-07-768x480.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-41-07-624x390.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-41-07.png 1449w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81303\" class=\"wp-caption-text\">DTO Constructor Projection Query<\/p><\/div>\n<p>Benefits:<\/p>\n<ol>\n<li>Smaller SQL<\/li>\n<li>Less memory usage<\/li>\n<li>Faster serialization<\/li>\n<li>No accidental lazy loads<\/li>\n<\/ol>\n<p>For heavy reads, consider dedicated read models or CQRS-style projections.<\/p>\n<h1>4. Batch Fetching<\/h1>\n<p>Batch fetching reduces lazy-loading chatter with minimal mapping changes.<\/p>\n<div id=\"attachment_81304\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81304\" class=\"size-large wp-image-81304\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-43-16-1024x677.png\" alt=\"@BatchSize Collection Mapping\" width=\"625\" height=\"413\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-43-16-1024x677.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-43-16-300x198.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-43-16-768x508.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-43-16-624x413.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-43-16.png 1440w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81304\" class=\"wp-caption-text\">@BatchSize Collection Mapping<\/p><\/div>\n<div id=\"attachment_81305\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81305\" class=\"size-large wp-image-81305\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-44-19-1024x631.png\" alt=\"Global Batch Fetch Size Property\" width=\"625\" height=\"385\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-44-19-1024x631.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-44-19-300x185.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-44-19-768x473.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-44-19-624x384.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-44-19.png 1461w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81305\" class=\"wp-caption-text\">Global Batch Fetch Size Property<\/p><\/div>\n<div id=\"attachment_81306\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81306\" class=\"size-large wp-image-81306\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-45-47-1024x668.png\" alt=\"Batch Fetch vs Per-Parent Lazy Queries \" width=\"625\" height=\"408\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-45-47-1024x668.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-45-47-300x196.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-45-47-768x501.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-45-47-624x407.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-09-23-45-47.png 1422w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81306\" class=\"wp-caption-text\">Batch Fetch vs Per-Parent Lazy Queries<\/p><\/div>\n<p>Excellent legacy mitigation\u2014not always the long-term design for hot APIs.<\/p>\n<h1>5. FetchMode.SUBSELECT<\/h1>\n<p>Useful for broad in-session graphs, weaker for precise API projections. Second-level cache is not an N+1 strategy\u2014it does not replace fetch planning.<\/p>\n<div id=\"attachment_81308\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81308\" class=\"size-large wp-image-81308\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-05-11-1024x645.png\" alt=\"FetchMode.SUBSELECT Mapping\" width=\"625\" height=\"394\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-05-11-1024x645.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-05-11-300x189.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-05-11-768x484.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-05-11-624x393.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-05-11.png 1503w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81308\" class=\"wp-caption-text\">FetchMode.SUBSELECT Mapping<\/p><\/div>\n<div id=\"attachment_81309\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81309\" class=\"size-large wp-image-81309\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-06-28-1024x645.png\" alt=\"SUBSELECT Collection SQL\" width=\"625\" height=\"394\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-06-28-1024x645.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-06-28-300x189.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-06-28-768x484.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-06-28-624x393.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-06-28.png 1503w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81309\" class=\"wp-caption-text\">SUBSELECT Collection SQL<\/p><\/div>\n<h1>Production Challenges<\/h1>\n<p><strong>MultipleBagFetchException<\/strong>: fetching multiple List collections with JOIN FETCH can fail. Prefer separate queries, DTOs or batching. Switching to Set may avoid the exception, not cartesian cost.<\/p>\n<p>For paged APIs with child data avoid JOIN Orders LIMIT 20. Use a two-step pattern:<\/p>\n<div id=\"attachment_81310\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81310\" class=\"size-large wp-image-81310\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-09-08-1024x657.png\" alt=\"Two-Step Pagination with Child Data\" width=\"625\" height=\"401\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-09-08-1024x657.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-09-08-300x193.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-09-08-768x493.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-09-08-624x400.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-09-08.png 1446w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81310\" class=\"wp-caption-text\">Two-Step Pagination with Child Data<\/p><\/div>\n<p>The same anti-pattern appears across services:<\/p>\n<div id=\"attachment_81311\" style=\"width: 635px\" class=\"wp-caption alignleft\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-81311\" class=\"size-large wp-image-81311\" src=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-10-17-1024x664.png\" alt=\"Database N+1 vs Microservice N+1\" width=\"625\" height=\"405\" srcset=\"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-10-17-1024x664.png 1024w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-10-17-300x195.png 300w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-10-17-768x498.png 768w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-10-17-624x405.png 624w, https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-10-00-10-17.png 1465w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><p id=\"caption-attachment-81311\" class=\"wp-caption-text\">Database N+1 vs Microservice N+1<\/p><\/div>\n<p>Use bulk APIs, batching, caching, or read models. Avoid chatty communication.<\/p>\n<h1>Decision Guide<\/h1>\n<p><strong>1. JOIN FETCH<\/strong><br \/>\n<strong>Use when: <\/strong>You need a bounded parent + one collection and managed entities.<\/p>\n<p><strong>Avoid when: <\/strong>Paginating joined collections or fetching multiple List bags.<\/p>\n<p><strong>Why: <\/strong>It reduces round trips, but joins can multiply result rows and create pagination or cartesian-product problems.<\/p>\n<p><strong>2. DTO Projection<\/strong><br \/>\n<strong>Use when: <\/strong>Building REST\/read APIs that need only specific fields.<\/p>\n<p><strong>Avoid when: <\/strong>You need fully managed entities for further in-place changes.<\/p>\n<p><strong>Why: <\/strong>It keeps SQL narrow, reduces memory usage, improves serialization and prevents accidental lazy loading.<\/p>\n<p><strong>3. EntityGraph<\/strong><br \/>\n<strong>Use when: <\/strong>Different repository methods need different fetch graphs while entity mappings remain LAZY.<\/p>\n<p><strong>Avoid when: <\/strong>The use case is better represented by a narrow DTO projection.<\/p>\n<p><strong>Why: <\/strong>It lets the repository define the fetch plan without duplicating JPQL.<\/p>\n<p><strong>4. Batch Fetching \/ SUBSELECT<\/strong><br \/>\n<strong>Use when: <\/strong>You need a low-change mitigation for existing lazy-loading patterns.<\/p>\n<p><strong>Avoid when: <\/strong>A hot API path requires precisely optimized SQL.<\/p>\n<p><strong>Why: <\/strong>It reduces N+1 query chatter but does not replace deliberate fetch planning.<\/p>\n<p><strong>5. Separate Queries \/ DTOs<\/strong><br \/>\n<strong>Use when: <\/strong>The API needs multiple collections or paginated parent\/child data.<\/p>\n<p><strong>Avoid when: <\/strong>You can safely satisfy the use case with a single bounded fetch.<\/p>\n<p><strong>Why: <\/strong>Separate queries prevent multi-collection JOIN FETCH problems and give you better control over result-set size.<\/p>\n<h1>Best Practices<\/h1>\n<ol>\n<li>Keep associations LAZY by default, explicitly set @ManyToOne(fetch = LAZY) when appropriate.<\/li>\n<li>Define fetch plans per use case, return DTOs from API boundaries.<\/li>\n<li>Treat query count as an NFR for critical APIs, enforce CI query budgets.<\/li>\n<li>Index FK\/join columns, load-test with production-like data volumes.<\/li>\n<li>Prefer disabling OSIV and loading inside transactional service boundaries.<\/li>\n<li>Design bulk service APIs to prevent distributed HTTP N+1.<\/li>\n<\/ol>\n<h1>Conclusion<\/h1>\n<p>N+1 is a <strong>database communication design problem<\/strong> exposed by ORM convenience. Choose JOIN FETCH, EntityGraph, DTOs, batching\/SUBSELECT or read models by use case\u2014not by habit. Do not let entity navigation silently decide database traffic. Design fetch strategies intentionally and prove them with SQL and query-count gates.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to &#8220;Return all customers with their orders.&#8221; The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API [&hellip;]<\/p>\n","protected":false},"author":2132,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":6,"footnotes":""},"categories":[446],"tags":[4843,265,5902,5655,8815,2683,6008,2072,558],"class_list":["post-81050","post","type-post","status-publish","format-standard","hentry","category-java","tag-database","tag-hibernate","tag-jpa","tag-lazyloading","tag-orm","tag-performance","tag-queryoptimization","tag-springboot","tag-sql"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to &quot;Return all customers with their orders.&quot; The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Rajdeep Dabral\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"TO THE NEW BLOG\" \/>\n\t\t<meta property=\"og:type\" content=\"blog\" \/>\n\t\t<meta property=\"og:title\" content=\"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog\" \/>\n\t\t<meta property=\"og:description\" content=\"Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to &quot;Return all customers with their orders.&quot; The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/2thenew.xyz\/blog\/wp-content\/themes\/ttn\/images\/social-logo.png\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/2thenew.xyz\/blog\/wp-content\/themes\/ttn\/images\/social-logo.png\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:site\" content=\"@tothenew\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog\" \/>\n\t\t<meta name=\"twitter:description\" content=\"Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to &quot;Return all customers with their orders.&quot; The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API\" \/>\n\t\t<meta name=\"twitter:image\" content=\"https:\/\/2thenew.xyz\/blog\/wp-content\/themes\/ttn\/images\/social-logo.png\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#article\",\"name\":\"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog\",\"headline\":\"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices\",\"author\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/author\\\/rajdeep-dabral\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/wp-ttn-blog\\\/uploads\\\/2026\\\/08\\\/Screenshot-from-2026-08-03-14-39-42-1024x432.png\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#articleImage\"},\"datePublished\":\"2026-09-02T11:09:08+05:30\",\"dateModified\":\"2026-09-09T10:42:09+05:30\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#webpage\"},\"articleSection\":\"Java\\\/JVM, Database, hibernate, JPA, lazyloading, ORM, performance, QueryOptimization, SpringBoot, SQL\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.tothenew.com\\\/blog\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/category\\\/java\\\/#listItem\",\"name\":\"Java\\\/JVM\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/category\\\/java\\\/#listItem\",\"position\":2,\"name\":\"Java\\\/JVM\",\"item\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/category\\\/java\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#listItem\",\"name\":\"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#listItem\",\"position\":3,\"name\":\"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/category\\\/java\\\/#listItem\",\"name\":\"Java\\\/JVM\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/#organization\",\"name\":\"TO THE NEW Blog\",\"url\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/author\\\/rajdeep-dabral\\\/#author\",\"url\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/author\\\/rajdeep-dabral\\\/\",\"name\":\"Rajdeep Dabral\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#authorImage\",\"url\":\"https:\\\/\\\/newersworld-sf-static.tothenew.net\\\/prod\\\/profilePicFolder\\\/def636fc-d6ca-4daf-898c-86caee310fbc_3657-Rajdeep-Dabral-PROFILEPICTURE.jpeg\",\"width\":96,\"height\":96,\"caption\":\"Rajdeep Dabral\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#webpage\",\"url\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/\",\"name\":\"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog\",\"description\":\"Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to \\\"Return all customers with their orders.\\\" The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/author\\\/rajdeep-dabral\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/author\\\/rajdeep-dabral\\\/#author\"},\"datePublished\":\"2026-09-02T11:09:08+05:30\",\"dateModified\":\"2026-09-09T10:42:09+05:30\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/\",\"name\":\"TO THE NEW Blog\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.tothenew.com\\\/blog\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog","description":"Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to \"Return all customers with their orders.\" The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API","canonical_url":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#article","name":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog","headline":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices","author":{"@id":"https:\/\/2thenew.xyz\/blog\/author\/rajdeep-dabral\/#author"},"publisher":{"@id":"https:\/\/2thenew.xyz\/blog\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/2thenew.xyz\/blog\/wp-ttn-blog\/uploads\/2026\/08\/Screenshot-from-2026-08-03-14-39-42-1024x432.png","@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#articleImage"},"datePublished":"2026-09-02T11:09:08+05:30","dateModified":"2026-09-09T10:42:09+05:30","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#webpage"},"isPartOf":{"@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#webpage"},"articleSection":"Java\/JVM, Database, hibernate, JPA, lazyloading, ORM, performance, QueryOptimization, SpringBoot, SQL"},{"@type":"BreadcrumbList","@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/2thenew.xyz\/blog#listItem","position":1,"name":"Home","item":"https:\/\/2thenew.xyz\/blog","nextItem":{"@type":"ListItem","@id":"https:\/\/2thenew.xyz\/blog\/category\/java\/#listItem","name":"Java\/JVM"}},{"@type":"ListItem","@id":"https:\/\/2thenew.xyz\/blog\/category\/java\/#listItem","position":2,"name":"Java\/JVM","item":"https:\/\/2thenew.xyz\/blog\/category\/java\/","nextItem":{"@type":"ListItem","@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#listItem","name":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices"},"previousItem":{"@type":"ListItem","@id":"https:\/\/2thenew.xyz\/blog#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#listItem","position":3,"name":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices","previousItem":{"@type":"ListItem","@id":"https:\/\/2thenew.xyz\/blog\/category\/java\/#listItem","name":"Java\/JVM"}}]},{"@type":"Organization","@id":"https:\/\/2thenew.xyz\/blog\/#organization","name":"TO THE NEW Blog","url":"https:\/\/2thenew.xyz\/blog\/"},{"@type":"Person","@id":"https:\/\/2thenew.xyz\/blog\/author\/rajdeep-dabral\/#author","url":"https:\/\/2thenew.xyz\/blog\/author\/rajdeep-dabral\/","name":"Rajdeep Dabral","image":{"@type":"ImageObject","@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#authorImage","url":"https:\/\/newersworld-sf-static.tothenew.net\/prod\/profilePicFolder\/def636fc-d6ca-4daf-898c-86caee310fbc_3657-Rajdeep-Dabral-PROFILEPICTURE.jpeg","width":96,"height":96,"caption":"Rajdeep Dabral"}},{"@type":"WebPage","@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#webpage","url":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/","name":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog","description":"Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to \"Return all customers with their orders.\" The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/2thenew.xyz\/blog\/#website"},"breadcrumb":{"@id":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/#breadcrumblist"},"author":{"@id":"https:\/\/2thenew.xyz\/blog\/author\/rajdeep-dabral\/#author"},"creator":{"@id":"https:\/\/2thenew.xyz\/blog\/author\/rajdeep-dabral\/#author"},"datePublished":"2026-09-02T11:09:08+05:30","dateModified":"2026-09-09T10:42:09+05:30"},{"@type":"WebSite","@id":"https:\/\/2thenew.xyz\/blog\/#website","url":"https:\/\/2thenew.xyz\/blog\/","name":"TO THE NEW Blog","inLanguage":"en-US","publisher":{"@id":"https:\/\/2thenew.xyz\/blog\/#organization"}}]},"og:locale":"en_US","og:site_name":"TO THE NEW BLOG","og:type":"blog","og:title":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog","og:description":"Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to &quot;Return all customers with their orders.&quot; The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API","og:url":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/","og:image":"https:\/\/2thenew.xyz\/blog\/wp-content\/themes\/ttn\/images\/social-logo.png","og:image:secure_url":"https:\/\/2thenew.xyz\/blog\/wp-content\/themes\/ttn\/images\/social-logo.png","twitter:card":"summary","twitter:site":"@tothenew","twitter:title":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices | TO THE NEW Blog","twitter:description":"Introduction A production incident often starts with something that looks harmless. A developer ships a Spring Boot API to &quot;Return all customers with their orders.&quot; The code is simple, the response looks correct and everything works perfectly in development. Then traffic grows and the same endpoint causes: Database CPU spikes Connection pool exhaustion Higher API","twitter:image":"https:\/\/2thenew.xyz\/blog\/wp-content\/themes\/ttn\/images\/social-logo.png"},"aioseo_meta_data":{"post_id":"81050","title":null,"description":null,"keywords":null,"keyphrases":{"focus":{"keyphrase":"","score":0,"analysis":{"keyphraseInTitle":{"score":0,"maxScore":9,"error":1}}},"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"Article","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":null,"frequency":"default","local_seo":null,"limit_modified_date":false,"created":"2026-08-01 04:45:46","updated":"2026-09-09 05:12:13","focus_keyword":null,"additional_keywords":null,"truseo_locale":null,"ai":{"faqs":[],"keyPoints":[],"schemas":[],"titles":[],"descriptions":[],"socialPosts":{"email":{"subject":"","preview":"","content":""},"linkedin":[],"twitter":[],"facebook":[],"instagram":[]}},"breadcrumb_settings":null,"seo_analyzer_scan_date":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/2thenew.xyz\/blog\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/2thenew.xyz\/blog\/category\/java\/\" title=\"Java\/JVM\">Java\/JVM<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tHibernate N+1 Query Problem: Causes, Solutions and Production Best Practices\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/2thenew.xyz\/blog"},{"label":"Java\/JVM","link":"https:\/\/2thenew.xyz\/blog\/category\/java\/"},{"label":"Hibernate N+1 Query Problem: Causes, Solutions and Production Best Practices","link":"https:\/\/2thenew.xyz\/blog\/hibernate-n1-query-problem-causes-solutions-and-production-best-practices\/"}],"_links":{"self":[{"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/posts\/81050","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/users\/2132"}],"replies":[{"embeddable":true,"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/comments?post=81050"}],"version-history":[{"count":36,"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/posts\/81050\/revisions"}],"predecessor-version":[{"id":82850,"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/posts\/81050\/revisions\/82850"}],"wp:attachment":[{"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/media?parent=81050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/categories?post=81050"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/2thenew.xyz\/blog\/wp-json\/wp\/v2\/tags?post=81050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}