The hidden query storm
GraphQL resolvers run per field, per object. Fetch a list of authors, then ask for each author's books, and a naive resolver issues one query for the authors plus one query for every author's books. That is the N plus one problem, and it scales poorly.
Why it happens
Each resolver fires independently and has no view of its siblings. Resolving books for author one knows nothing about books for author two, so it cannot combine the lookups, producing many tiny queries.
How batching fixes it
A DataLoader sits between resolvers and the data source. Within a single tick it collects all the requested ids, then issues one batched query for the whole set and hands each resolver its slice. It also caches within a request so a repeated id is fetched once.
Key idea
Per field resolvers cause N plus one queries, and a per request batching loader collapses them into one query per layer.