PostgreSQL или MongoDB для backend: как выбрать базу данных
Автор: Казачкин Даниил Михайлович · Обновлено
PostgreSQL и MongoDB нельзя честно сравнить по шкале «старая реляционная база против современной нереляционной». PostgreSQL сочетает таблицы, ограничения, JOIN и транзакции с типом jsonb. MongoDB хранит BSON-документы, предлагает встраивание и ссылки и также поддерживает транзакции. Выбор начинается с инвариантов и профиля нагрузки конкретного backend, а не с жанра проекта.
Короткий ответ
PostgreSQL обычно является понятной отправной точкой, когда важны связи между сущностями, ограничения целостности, сложные выборки и согласованные изменения нескольких записей. MongoDB особенно естественна, когда основная единица чтения и записи — документ с вложенными данными, его границы устойчивы, а доступ проектируется вокруг известных сценариев.
Это не взаимоисключающие возможности. Документы можно хранить в jsonb PostgreSQL, связи — ссылками между коллекциями MongoDB, а обе системы индексируют данные и выполняют транзакционные операции. Решение определяет не наличие функции, а то, насколько модель делает частые и критичные операции простыми, проверяемыми и дешёвыми.
Начните с инвариантов, а не с формата JSON
Запишите правила, нарушение которых недопустимо: email пользователя уникален; заказ относится к существующему клиенту; остаток не отрицателен; платёж и смена статуса должны завершиться вместе. В PostgreSQL часть этих правил прямо выражается ограничениями.
CREATE TABLE customers (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
email text NOT NULL UNIQUE
);
CREATE TABLE orders (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
customer_id bigint NOT NULL REFERENCES customers(id),
status text NOT NULL CHECK (status IN ('new', 'paid', 'cancelled')),
total numeric(12, 2) NOT NULL CHECK (total >= 0),
metadata jsonb NOT NULL DEFAULT '{}'::jsonb
);Схема одновременно фиксирует связи и оставляет место для необязательных метаданных. Если правила естественно описываются ключами, ссылочной целостностью и объединением таблиц, реляционная модель уменьшает объём проверок в приложении.
Когда документ является правильной границей
В MongoDB связанные данные можно встроить в один документ. Это удобно, если backend почти всегда получает заказ вместе с его строками, строки не живут независимо, а размер массива остаётся управляемым.
{
_id: ObjectId("..."),
customerId: ObjectId("..."),
status: "paid",
createdAt: ISODate("2026-08-28T12:00:00Z"),
items: [
{ productId: ObjectId("..."), quantity: 2, unitPrice: Decimal128("19.90") },
{ productId: ObjectId("..."), quantity: 1, unitPrice: Decimal128("7.50") }
]
}Встраивание позволяет получить агрегат одним чтением и обновлять связанные поля в границе одного документа. Цена — возможное дублирование и необходимость продумать рост вложенных коллекций. Гибкая схема не отменяет моделирование: официальная методика MongoDB также начинает с нагрузки, отношений, паттернов и индексов.
Связи: JOIN, ссылки и встраивание
В PostgreSQL нормализованные сущности соединяют JOIN. Это удобно для меняющихся вопросов к данным: отчёты по клиентам, заказам, товарам и периодам можно собирать из одних отношений, сохраняя ключи и ограничения.
В MongoDB есть два основных выбора: встроить связанные данные или хранить ссылку. Ссылка уместна, когда сущность часто запрашивается отдельно, отношение велико или встраивание создаёт неоправданное дублирование. Данные из коллекций можно объединять через aggregation, в том числе $lookup, но частая необходимость собирать множество нормализованных частей — сигнал проверить границы документов.
Не считайте «нет JOIN» достоинством или недостатком само по себе. Сначала перечислите пять самых частых чтений и записей, затем проверьте, сколько документов, таблиц, сетевых обращений и конкурентных изменений требует каждая модель.
Транзакции и согласованность
Обе системы поддерживают транзакции, но модель данных влияет на то, как часто они нужны. В PostgreSQL изменение связанных таблиц обычно оформляют одной транзакцией, а ограничения проверяет база. В MongoDB атомарность изменения одного документа делает хорошо выбранную документную границу особенно ценной; для операций по нескольким документам доступны транзакции с отдельными эксплуатационными условиями.
Неверный вывод — выбирать MongoDB потому, что «транзакций нет», или отвергать её по той же причине. Правильный вопрос: какие данные изменяются вместе, как обрабатываются конфликты и повторные попытки и что увидит читатель при частичном отказе.
Гибкость схемы и эволюция данных
MongoDB позволяет документам одной коллекции иметь разные наборы полей, что удобно при постепенном развитии неоднородных объектов. Но приложение всё равно должно понимать версии, обязательность полей и способ миграции старых документов. Большой production-набор данных не становится простым для изменения только из-за отсутствия обязательной таблицы.
PostgreSQL требует явнее управлять структурой таблиц, зато схема, типы и ограничения делают контракт данных наблюдаемым. Для действительно вариативной части можно использовать jsonb, не превращая все поля в один непрозрачный документ. Компромисс оценивают по запросам: часто фильтруемые и связанные атрибуты обычно полезно моделировать явно.
Матрица решения для backend
Выберите PostgreSQL как исходную гипотезу, если большинство утверждений верны:
- много устойчивых связей и выборок между сущностями;
- целостность удобно выразить UNIQUE, CHECK и FOREIGN KEY;
- нужны разнообразные отчёты и меняющиеся аналитические запросы;
- несколько строк или таблиц часто изменяются согласованно;
- команда уверенно проектирует SQL, миграции и планы запросов.
Проверьте MongoDB как исходную гипотезу, если большинство утверждений верны:
- документ совпадает с агрегатом приложения и обычно читается целиком;
- вложенные данные принадлежат родителю и имеют контролируемый рост;
- основные query shapes известны заранее и под них можно спроектировать документы и индексы;
- разные виды документов действительно требуют отличающихся полей;
- команда умеет управлять дублированием, ссылками и эволюцией документов.
Если ответы смешанные, проведите небольшой прототип на двух самых тяжёлых чтениях и одной критичной записи. Сравнивайте не синтетическую вставку миллиона пустых объектов, а полноту инвариантов, сложность кода, план запроса, задержку и поведение при отказе.
Типичные ошибочные аргументы
«У нас JSON API, значит нужна MongoDB» — транспортный JSON не определяет модель хранения. «Схема будет меняться, значит PostgreSQL не подходит» — реляционные схемы эволюционируют миграциями, а jsonb покрывает вариативные фрагменты. «MongoDB автоматически масштабирует любой запрос» — результат зависит от модели, индексов, распределения и операции. «PostgreSQL всегда обеспечивает целостность» — только если команда действительно задала ограничения и корректные транзакционные границы.
Ещё одна ошибка — выбирать технологию по единственной будущей возможности. Цена решения платится каждый день в разработке, диагностике, резервном копировании, обновлениях и найме. Возможность должна соответствовать вероятной нагрузке и компетенциям команды.
Практика: решение для сервиса заказов
Составьте таблицу из трёх сценариев: показать историю клиента за год, оформить заказ с резервированием остатков, обновить описание товара. Для каждого варианта хранения запишите:
- границу атомарного изменения;
- способ гарантировать существование клиента и уникальность email;
- число сущностей, которые читает запрос;
- необходимые индексы;
- поведение при повторе после тайм-аута;
- план изменения схемы через год.
После этого реализуйте только оформление заказа и самый тяжёлый список на обеих моделях. Решение считается обоснованным, если команда может показать инварианты и измерения, а не только сравнительную таблицу возможностей.
Что важно запомнить
PostgreSQL против MongoDB — это выбор модели и эксплуатационных компромиссов, а не победителя брендов. Сначала фиксируют инварианты, границы агрегатов и query shapes, затем проектируют индексы и проверяют критичные операции. Хорошее решение объясняется данными и отказами, а не лозунгом «SQL или NoSQL».
Связанные исследования
- B-tree и планировщик PostgreSQL: почему индекс не обязан ускорять запрос — Связываем устройство B-tree с cost-based planner PostgreSQL: селективность, составные индексы, EXPLAIN ANALYZE, статистика и пределы index-only scan.