October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

N+1 Queries Explained: Why One API Request Can Trigger 101 Database Calls

A list API can trigger one extra SELECT per record when it touches a lazy relationship. Learn how eager loading helps and how to verify the actual SQL.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

An API endpoint that appears to fetch a list once can issue many more database queries when it reads a lazy-loaded relationship for every returned record. With 100 parent records, one initial query plus one related-record query per parent makes 101 SELECT statements. Eager loading can batch the relationship reads, but the actual count depends on the framework, relationship shape, and response code.

How the N+1 query problem happens

An ORM may fetch parent records without fetching their related records. If response serialization or other application code then accesses a lazy relationship on each parent, the ORM can run another SELECT for each access. The result is one query for the list plus N queries for related data: N+1.

As an Amazon Associate I earn from qualifying purchases.

For example, fetching 100 books and then lazily reading each book’s author can produce one query for the books and 100 more for authors. The “101 instead of 2” framing is an arithmetic illustration, not a guaranteed query count or benchmark. SQLAlchemy’s relationship-loading documentation describes the same N+1 effect: accessing lazy-loaded attributes on N loaded objects can emit N+1 SELECT statements.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Laravel’s Eloquent documentation gives a concrete code example: retrieving 25 books and accessing each author results in 26 queries. In that example, eager loading authors reduces the count to two. Those figures illustrate the pattern; they are not a universal result for every endpoint or loading strategy.

#1 Best Overall

How to fix N+1 queries

Load the relationships the API response actually needs at the point where it queries the parent records. Do not indiscriminately load every relationship: eager loading is a specific choice of which related data to fetch, and nested or reverse access can still trigger additional queries.

SQLAlchemy: choose a loader for the relationship

SQLAlchemy 2.1 provides selectinload() and joinedload() as common eager-loading options. For collections, its documentation describes select-in loading as the simplest and most efficient approach in most cases. It fetches related rows in a separate SELECT using parent keys in an IN clause; one relationship often takes two statements total, though batches and additional relationships can change that count.

joinedload() loads related rows through a JOIN in the same result set. It can be appropriate for a suitable relationship, but joining a collection can multiply result rows and duplicate parent data. An explicit Select.join() and joinedload() are not interchangeable: an explicit join can affect which rows qualify, while the loader option is intended to load related objects without changing the primary result set. SQLAlchemy also takes special steps around modifiers such as DISTINCT, LIMIT, or OFFSET when using joined eager loading.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

There is a backend caveat for select-in loading: SQLAlchemy documents that it is not feasible for composite primary keys when the database does not support tuple IN, identifying SQL Server as such a backend. The documentation notes that subquery loading may be useful for that case.

For example, a SQLAlchemy query can specify a relationship up front with selectinload() or joinedload(), depending on its shape and requirements. Use raiseload() where appropriate during development or testing to make an unexpected lazy load raise an error instead of silently issuing another SELECT.

Laravel Eloquent: eager-load the response relationship

In Laravel’s documented example, Book::with('author')->get() eager-loads authors for the returned books. This changes the example from one books query plus a query per author access to a batched relationship load.

Eager loading one direction does not automatically prevent every N+1 pattern. Laravel notes that loading posts with comments does not by itself hydrate each comment’s parent post; accessing that parent from inside a comments loop can still repeat queries. Its chaperone() relationship option addresses that parent-hydration case.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How to choose between joined and batched loading

Approach Typical query shape Useful considerations
Joined eager loading A JOIN brings related data into the parent result set. Can suit appropriate relationships, but collection joins may expand rows and duplicate parent data. Keep result semantics and pagination modifiers in view.
Batched or select-in loading A parent SELECT followed by one or more relationship SELECTs, commonly using parent keys in an IN clause. Avoids joined row expansion for collections, at the cost of extra statements. SQLAlchemy documents a composite-key limitation on backends without tuple IN support, including SQL Server.

The right choice depends on relationship cardinality, backend support, and the result the endpoint must return. A scalar many-to-one relationship and a large one-to-many collection need not use the same strategy. Fewer statements alone do not establish lower total latency in every workload, so verify the endpoint’s behavior rather than optimizing a query count in isolation.

A practical way to find and verify the problem

  1. Reproduce the endpoint. Use a representative list size and the same response shape that causes the concern.
  2. Inspect executed SQL. Use your framework’s query logging or a profiler to see whether the same relationship SELECT repeats with different parent keys. Source code that contains one apparent fetch does not reveal all lazy loads triggered while building the response.
  3. Identify relationships the response reads. Include fields touched by serializers, resource classes, templates, or nested loops—not only relationships named in the endpoint’s main query.
  4. Choose an appropriate loader. Select joined or batched loading based on relationship shape, cardinality, backend behavior, and whether changing the query’s qualifying rows would be correct.
  5. Run the endpoint again and inspect both SQL and output. Confirm that the repeated statements are gone and that the response still contains the expected records and relationship data. Where it suits the codebase, add regression coverage for query-count behavior.
  6. Check nested and reverse access. A fix for a forward relationship may leave another repeated query in a loop that reads from children back to their parent.

The query count varies with page size, the number of relationships accessed, nested reads, framework behavior, batching, and loading strategy. Treat 101-to-2 as a useful mental model for one parent query plus one batched relationship query—not as a promise that every eager-loading change produces exactly two statements.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.