20. Оптимизация запросов
Производительность — критически важный аспект любого приложения, работающего с базой данных. Prisma предоставляет инструменты для диагностики и устранения проблем с производительностью.
Проблема N+1
Заголовок раздела «Проблема N+1»N+1 — одна из самых частых проблем ORM. Она возникает, когда для получения N связанных записей выполняется N+1 отдельных запросов вместо одного:
// ❌ ПЛОХО — N+1 проблема (1 запрос + N запросов)const posts = await prisma.post.findMany() // 1 запросfor (const post of posts) { const author = await prisma.user.findUnique({ // N запросов! where: { id: post.authorId }, })}
// ✅ ХОРОШО — один запрос с JOINconst posts = await prisma.post.findMany({ include: { author: true }, // 1 запрос с JOIN})Выборочная загрузка полей
Заголовок раздела «Выборочная загрузка полей»Вместо загрузки всех полей используйте select:
// ❌ Загружаем все поля включая большие blobsconst users = await prisma.user.findMany()
// ✅ Загружаем только нужные поляconst users = await prisma.user.findMany({ select: { id: true, name: true, email: true, // avatar: false — не загружаем blob },})Индексы
Заголовок раздела «Индексы»Индексы критически важны для производительности. Всегда индексируйте поля, по которым фильтруете:
model Post { id Int @id authorId Int title String createdAt DateTime
// Индекс для запросов WHERE authorId = X ORDER BY createdAt @@index([authorId, createdAt])
// Индекс для полнотекстового поиска @@index([title])}Connection Pooling
Заголовок раздела «Connection Pooling»Настройте пул соединений для вашей нагрузки:
DATABASE_URL="postgresql://user:pass@localhost/db?connection_limit=10&pool_timeout=20"Пагинация вместо loadAll
Заголовок раздела «Пагинация вместо loadAll»// ❌ Загружать всё — плохая идея для больших таблицconst all = await prisma.post.findMany()
// ✅ Использовать пагинациюconst page = await prisma.post.findMany({ skip: 0, take: 20,})