Какие ошибки делают команды, когда прячут сложность базы данных за Prisma?
Главные ошибки: N+1 при итерации с запросами внутри цикла, SELECT * без явного select, блокирующие миграции без CONCURRENTLY, отсутствие транзакций там, где они нужны, и нехватка индексов на полях фильтрации.
Когда Prisma становится абстракцией над хаосом
Prisma отлично снижает порог входа — не нужно писать SQL руками, схема читается как документация, типы генерируются автоматически. Но именно эта лёгкость провоцирует паттерны, которые превращают базу данных в узкое место в продакшене.
Ошибка 1: игнорирование N+1
Самая распространённая проблема. Разработчик пишет:
const users = await prisma.user.findMany();
for (const user of users) {
const posts = await prisma.post.findMany({
where: { authorId: user.id },
});
}
100 пользователей = 101 запрос к БД. Prisma не объединяет эти запросы автоматически. Правильно — использовать include или select с вложенными связями:
const users = await prisma.user.findMany({
include: {
posts: true,
},
});
Но даже include не всегда генерирует JOIN — Prisma может делать отдельный SELECT для связей типа «один-ко-многим». Это нужно проверять через лог.
Ошибка 2: SELECT * везде
По умолчанию Prisma выбирает все поля. Если в таблице есть avatar bytea, description text или JSON-колонки, они тянутся при каждом запросе. В API, который возвращает список из 50 строк, это могут быть мегабайты лишних данных.
// Плохо
const users = await prisma.user.findMany();
// Хорошо
const users = await prisma.user.findMany({
select: {
id: true,
name: true,
email: true,
},
});
Ошибка 3: миграции без анализа плана выполнения
Команды запускают prisma migrate deploy в продакшене и не думают о блокировках. Добавление NOT NULL колонки без DEFAULT блокирует таблицу. Создание индекса через миграцию без CONCURRENTLY блокирует запись.
-- Prisma сгенерирует это:
CREATE INDEX "User_email_idx" ON "User"("email");
-- Нужно вручную заменить на:
CREATE INDEX CONCURRENTLY "User_email_idx" ON "User"("email");
Prisma не поддерживает CONCURRENTLY в схеме — это нужно делать через raw SQL в кастомных миграциях.
Ошибка 4: транзакции везде и нигде
Два крайних случая: либо весь код без транзакций (данные в несогласованном состоянии при сбое в середине операции), либо гигантские транзакции, которые держат блокировки секундами. Prisma не навязывает транзакционную модель — разработчик должен думать о границах сам.
// Без транзакции — опасно
await prisma.order.create({ data: orderData });
await prisma.inventory.update({ where: { id }, data: { stock: { decrement: 1 } } });
// С транзакцией
await prisma.$transaction([
prisma.order.create({ data: orderData }),
prisma.inventory.update({ where: { id }, data: { stock: { decrement: 1 } } }),
]);
Ошибка 5: отсутствие индексов на часто используемых полях фильтрации
Prisma генерирует WHERE по любому полю — но индекса там нет, если он не указан в схеме явно. Многие команды не добавляют @@index вовремя:
model User {
id String @id @default(cuid())
email String @unique
teamId String
createdAt DateTime @default(now())
// Забыли добавить:
@@index([teamId, createdAt])
}
Ошибка 6: использование Prisma для аналитических запросов
Агрегации, оконные функции, CTE — Prisma поддерживает только базовые groupBy и aggregate. Команды пытаются реализовать аналитику через JS вместо SQL, что убивает производительность. Правильно — использовать $queryRaw для сложных запросов.
Подводные камни
- Prisma не предупреждает об N+1 в runtime — нужно явно включать логирование и смотреть количество запросов.
- Миграции Prisma в продакшене могут блокировать таблицы — нужен review каждого SQL в папке migrations/ перед деплоем.
- Отсутствие connection pooling на уровне приложения при serverless деплое приводит к исчерпанию соединений PostgreSQL — нужен Prisma Accelerate или pgBouncer.
prisma.$transactionс callback (interactive transaction) держит соединение всё время выполнения — долгие операции внутри приводят к пулу исчерпания.- Soft delete через middleware — популярный паттерн, но легко забыть применить его везде, особенно в
include-запросах. - Prisma не поддерживает partial indexes и expression indexes в schema.prisma — их нужно добавлять вручную в кастомных миграциях.
- Команды путают скорость разработки с производительностью — Prisma ускоряет первые, но не гарантирует вторую.
What hurts your answer
- Перечислять ошибки без объяснения причин
- Не отличать beginner mistakes от production failure modes
- Не предлагать процесс, который предотвращает повторение ошибок
What they're listening for
- Знает типичные ошибки при работе с Prisma
- Понимает причины ошибок
- Предлагает практики prevention и early detection