N+1 Problem & DataLoader — GraphQL

N+1 Problem & DataLoader Problem terbesar di GraphQL: nested resolvers menyebabkan N+1 queries. 10 users dengan posts = 1 query users + 10 queries posts…

N+1 Problem & DataLoader

Problem terbesar di GraphQL: nested resolvers menyebabkan N+1 queries. 10 users dengan posts = 1 query users + 10 queries posts.

Problem

query {
  users {        # 1 query: SELECT * FROM users
    name
    posts {      # N queries: SELECT * FROM posts WHERE author_id = ?
      title      # (dipanggil untuk SETIAP user)
    }
  }
}
# 10 users = 11 queries (1 + 10)

DataLoader

DataLoader batches dan caches individual loads. Semua .load(id) dalam satu tick di-batch menjadi satu query.

import DataLoader from "dataloader";

// Create loader (per request!)
const postsByAuthorLoader = new DataLoader(async (authorIds) => {
  // Satu query untuk semua author IDs
  const posts = await db.posts.findMany({
    where: { authorId: { in: authorIds } },
  });

  // Return array of results, same order as authorIds
  return authorIds.map(id => posts.filter(p => p.authorId === id));
});

// Resolver
User: {
  posts: (parent) => postsByAuthorLoader.load(parent.id),
}

// Sekarang: 10 users = 2 queries (1 users + 1 batched posts)

Setup di Context

// PENTING: DataLoader harus per-request (bukan global)
context: ({ req }) => ({
  user: getUser(req),
  loaders: {
    postsByAuthor: new DataLoader(batchPostsByAuthor),
    commentsByPost: new DataLoader(batchCommentsByPost),
    userById: new DataLoader(batchUsersById),
  },
})

// Resolver
User: {
  posts: (parent, _, { loaders }) => loaders.postsByAuthor.load(parent.id),
}

Rules

Yang akan kamu pelajari