PrismaJuniorExperience

Как сравнить Prisma с raw SQL, query builder и другими ORM по контролю, типобезопасности и производительности?

Raw SQL — максимальный контроль, нулевая типобезопасность. Kysely — баланс контроля и типов. Prisma — лучшая типобезопасность из коробки, меньше контроля над SQL. TypeORM/Sequelize — change tracking, но слабее типизированы.

Сравнение Prisma с raw SQL, query builder и другими ORM

Выбор инструмента для работы с базой данных — это компромисс между контролем, типобезопасностью и скоростью разработки. Разберём четыре подхода по трём осям.

Raw SQL

Контроль: максимальный. Вы пишете ровно тот SQL, который должна выполнить база. Window-функции, CTE, LATERAL JOIN, partial indexes — всё доступно без ограничений.

Типобезопасность: нулевая без дополнений. Строка SQL — это строка. Ошибки в именах колонок, типах и параметрах обнаруживаются только в runtime. Библиотека pg (node-postgres) возвращает any[].

Производительность: оптимальная. Нет overhead кодогенерации, нет трансформации запросов. Запрос попадает в базу ровно таким, каким написан.

import { Pool } from 'pg';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });

const { rows } = await pool.query<{ id: number; name: string }>(
  'SELECT id, name FROM users WHERE active = $1',
  [true]
);
// rows: { id: number; name: string }[] — ручная типизация

Query Builder (Knex.js, Kysely)

Контроль: высокий. Строите SQL программно, но имеете доступ к сырым выражениям. Kysely — современный типобезопасный query builder.

Типобезопасность: высокая (Kysely) или средняя (Knex). Kysely выводит типы результата из схемы, определённой разработчиком. Knex типизирован слабее.

// Kysely — типобезопасный query builder
import { Kysely, PostgresDialect } from 'kysely';

interface DB {
  users: { id: number; name: string; active: boolean };
}

const db = new Kysely<DB>({ dialect: new PostgresDialect({ pool }) });

const users = await db
  .selectFrom('users')
  .select(['id', 'name'])
  .where('active', '=', true)
  .execute();
// users: { id: number; name: string }[]

Prisma

Контроль: средний. CRUD и стандартные JOIN через include хорошо покрыты. Сложные запросы требуют $queryRaw, где теряется типобезопасность.

Типобезопасность: наивысшая из коробки. Типы генерируются автоматически из schema.prisma. Переименование поля ломает компиляцию во всех местах использования — это ценно при рефакторинге.

Производительность: хорошая для CRUD, требует внимания для аналитики. include иногда порождает несколько SELECT вместо JOIN. Overhead кодогенерации незначителен в runtime.

// Типобезопасно, лаконично, но SQL скрыт
const users = await prisma.user.findMany({
  where: { active: true },
  select: { id: true, name: true },
});
// users: { id: number; name: string }[]

Классические ORM (TypeORM, Sequelize, MikroORM)

Контроль: средний. Поддерживают QueryBuilder для сложных запросов. TypeORM имеет getRepository().createQueryBuilder() с поддержкой большинства SQL-конструкций.

Типобезопасность: средняя. TypeORM использует декораторы и reflection — типы могут расходиться с реальной схемой при неаккуратном использовании. MikroORM строже.

Change tracking: есть. Изменение поля сущности + flush() автоматически генерирует UPDATE. Это удобно, но создаёт скрытый overhead.

// TypeORM — entity mutation
const user = await userRepository.findOneBy({ id: 1 });
user.name = 'Alice'; // Change tracking
await userRepository.save(user); // Генерирует UPDATE только изменённых полей

Сводная таблица

  • Raw SQL — контроль 10/10, типобезопасность 2/10, скорость разработки 5/10.
  • Kysely — контроль 9/10, типобезопасность 9/10, скорость разработки 7/10.
  • Prisma — контроль 6/10, типобезопасность 10/10, скорость разработки 9/10.
  • TypeORM — контроль 7/10, типобезопасность 6/10, скорость разработки 7/10.

Подводные камни

  • Prisma $queryRaw разрушает типобезопасность — при переходе на raw запросы приходится вручную объявлять типы; ошибки в них не обнаруживаются компилятором.
  • TypeORM change tracking + ленивые загрузки — незамеченная ленивая загрузка связи внутри цикла — классический N+1, который тяжело обнаружить без логирования запросов.
  • Knex.js не обновляется активно — проект в режиме maintenance; для новых проектов предпочтительнее Kysely.
  • Миграции TypeORM в productionsynchronize: true удаляет колонки без предупреждения; использовать только в разработке.
  • Prisma не поддерживает все PostgreSQL-фичи в схеме — materialized views, custom types, partitioned tables — всё через raw SQL в миграциях, что нарушает единый source of truth.
  • Sequelize имеет сложную систему типов — TypeScript-поддержка добавлялась постфактум; типы менее строгие, чем у Prisma или Kysely.
  • Выбор инструмента зависит от нагрузки — для CRUD-приложения Prisma оптимальна; для аналитического сервиса с 50+ join-запросами в день лучше Kysely или raw SQL с типизацией через zod.

What hurts your answer

  • Объяснять Prisma только через определение, без задачи и границ применимости
  • Перечислять функции Prisma, но не показывать, какую проблему они решают
  • Называть Prisma универсальным выбором для любых проектов

What they're listening for

  • Понимает назначение Prisma, а не только определение
  • Связывает инструмент с классом задач и ограничениями
  • Умеет объяснить технологию простым языком

Related topics