StudyCode
N+1 — один запрос за списком и по одному запросу за связанными данными каждого элемента: загрузили 100 постов (1 запрос), потом в цикле по автору каждого (ещё 100). На дев-базе с 5 записями незаметно, в проде превращается в сотни запросов на один экран. Решения: JOIN — забрать всё одним запросом; батчинг — собрать id и сделать один WHERE id IN (...); в ORM — eager loading (include в Prisma, select_related в Django). Особенно коварна в GraphQL-резолверах и в циклах с await — ищите запросы к БД внутри for и map.
// ❌ N+1: 1 запрос за постами + 100 за авторами
const posts = await db.query('SELECT * FROM posts LIMIT 100');
for (const post of posts) {
post.author = await db.query(
'SELECT * FROM users WHERE id = $1', [post.author_id]
);
}
// ✅ Батчинг: 2 запроса всего
const ids = [...new Set(posts.map(p => p.author_id))];
const authors = await db.query(
'SELECT * FROM users WHERE id = ANY($1)', [ids]
);-- ✅ Или один запрос с JOIN
SELECT p.id, p.title, u.name AS author_name
FROM posts p
JOIN users u ON u.id = p.author_id
ORDER BY p.created_at DESC
LIMIT 100;