MAATRIX / Блог / Миф: NoSQL быстрее реляционной базы

Миф: NoSQL быстрее реляционной базы

MAATRIX

Рано или поздно на планёрке звучит фраза: "давайте на MongoDB, она быстрее, чем ваш PostgreSQL". Обычно это говорится без единого замера — просто потому что где-то читали статью 2013 года про facebook-масштаб. Разбираем, откуда взялся этот миф, в чём его реальное зерно и почему для большинства проектов с заказами, пользователями и связями между сущностями выбор в пользу NoSQL "по умолчанию" чаще создаёт проблемы, чем решает.

Откуда взялся миф и в чём его рациональное зерно

Миф про "NoSQL быстрее" родом из середины 2000-х — 2010-х, когда компании вроде Google, Amazon и Facebook публично рассказывали, как отказ от реляционных СУБД помог им масштабироваться. Публика услышала главное слово "быстрее" и не услышала контекст: речь шла об очень специфичных нагрузках — миллиарды записей в секунду, слабоструктурированные данные, распределённые кластеры на тысячах машин.

Рациональное зерно в мифе действительно есть, и его стоит признать честно:

  • Массовая запись слабоструктурированных документов. Если у вас поток логов, событий телеметрии, вложенных JSON-объектов без фиксированной схемы и без связей между записями — документная база вроде MongoDB или Cassandra действительно избавляет от накладных расходов на нормализацию и позволяет писать данные "как есть".
  • Горизонтальное шардирование из коробки. Многие NoSQL-решения проектировались с шардированием как первоклассной фичей: добавили узел — данные сами перераспределились по ключу шардирования. В классических реляционных СУБД шардирование — это либо ручная работа (Citus для PostgreSQL, партиционирование + прокси), либо отдельный слой поверх (Vitess для MySQL).
  • Простая модель "ключ → значение". Для кэшей, сессий, счётчиков — Redis и подобные key-value хранилища быстрее любой реляционной базы просто потому, что решают более узкую задачу без накладных расходов на SQL-парсер и планировщик запросов.

Проблема мифа не в этих пунктах — они правда работают. Проблема в обобщении "раз в этих сценариях NoSQL быстрее, значит она быстрее вообще, и современный проект должен выбирать её по умолчанию". Дальше разберём, почему это обобщение ломается.

Скорость определяет не SQL vs NoSQL, а соответствие модели данных запросам

Ключевая техническая ошибка мифа — попытка сравнивать парадигмы (SQL vs NoSQL) там, где на самом деле сравнение идёт между моделью данных и паттерном доступа к ним. СУБД — это инструмент, который либо соответствует форме ваших данных и характеру запросов, либо нет. Парадигма — это следствие модели данных, а не причина скорости.

Возьмём типичный пример: интернет-магазин с таблицами users, orders, order_items, products. Данные здесь по природе своей реляционные — заказ ссылается на пользователя и на товары, у одного заказа много позиций, у одного товара много заказов. Это классическая связь "многие-ко-многим" через промежуточную таблицу.

В PostgreSQL такой запрос — "все заказы пользователя с деталями товаров" — решается одним JOIN с индексами по внешним ключам:

SELECT o.id, o.created_at, p.name, oi.quantity, oi.price
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
JOIN products p ON p.id = oi.product_id
WHERE o.user_id = 42
ORDER BY o.created_at DESC;

При наличии индекса на orders(user_id) и первичных ключей на остальных таблицах планировщик PostgreSQL строит план из index scan + nested loop или hash join — это ровно та работа, для которой реляционная модель и была придумана: связывание нормализованных наборов данных по ключам.

Чтобы получить тот же результат в документной модели, у вас два варианта, и оба с компромиссами:

  1. Денормализация — хранить товары прямо внутри документа заказа. Тогда чтение заказа быстрое (один документ), но при изменении цены товара нужно обновлять её во всех документах заказов, где он упоминается — это уже не один UPDATE, а поиск и правка N документов.
  2. Ссылки между коллекциями (как в MongoDB $lookup) — по сути эмуляция JOIN на уровне приложения или агрегационного конвейера, которая обычно работает медленнее нативного JOIN реляционной СУБД именно потому, что не является для документной модели родной операцией.

Итог: для данных со связями реляционная модель с правильными индексами почти всегда эффективнее, чем повторение той же связности в базе, спроектированной для документов без связей. Дело не в том, что PostgreSQL "быстрее MongoDB" в вакууме — дело в том, что для этой формы данных реляционная модель ближе к предметной области.

Проверить это на своих данных просто:

EXPLAIN ANALYZE
SELECT o.id FROM orders o WHERE o.user_id = 42;

Если в плане вместо Index Scan вы видите Seq Scan — проблема не в СУБД, а в отсутствующем индексе, и переход на другую парадигму её не решит.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Где документные и key-value базы действительно быстрее — узкие сценарии

Чтобы не скатываться в другую крайность ("SQL всегда лучше"), стоит явно перечислить, где документная или key-value модель даёт реальное преимущество именно потому, что паттерн доступа ей соответствует:

СценарийПочему NoSQL подходитПример СУБД
Каталог с сильно разной структурой атрибутов у товаров разных категорийСхема действительно не фиксирована — навязывать общую таблицу со множеством NULL-колонок не имеет смыслаMongoDB
Хранение сессий, счётчиков, rate-limit, кэш ответов APIДоступ строго по одному ключу, без связей, критична задержка чтенияRedis
Поток событий/логов с последующей агрегациейЗапись доминирует над чтением, схема события со временем меняетсяCassandra, ClickHouse (аналитический профиль)
Граф связей "кто с кем связан" (соцсети, рекомендации)Обходы графа неудобно и медленно выражать через SQL JOIN на большой глубинеNeo4j и другие графовые СУБД

Обратите внимание: в каждой строке таблицы преимущество идёт не от "NoSQL как категории", а от конкретного свойства модели данных этой СУБД, совпадающего с характером задачи. Это подтверждает главный тезис статьи, а не опровергает его.

Если вы уже используете MongoDB и данные подошли под первый сценарий — почитайте про частые ошибки MongoDB на сервере, там разбираются типичные грабли с индексами и памятью, которые на практике съедают то самое преимущество в скорости.

PostgreSQL с JSONB стирает границу "гибкой схемы"

Второй технический момент, который миф игнорирует: современные реляционные СУБД давно умеют то, ради чего раньше выбирали NoSQL. В PostgreSQL тип JSONB позволяет хранить документ произвольной структуры прямо в колонке реляционной таблицы — с индексацией и выборкой по вложенным полям:

CREATE TABLE events (
    id BIGSERIAL PRIMARY KEY,
    user_id INT REFERENCES users(id),
    payload JSONB NOT NULL,
    created_at TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_events_payload ON events USING GIN (payload);

-- выборка по вложенному полю
SELECT * FROM events
WHERE payload @> '{"action": "checkout_started"}'
  AND user_id = 42;

GIN-индекс по JSONB даёт быстрый поиск по произвольным ключам документа — то есть ту самую "гибкую схему без миграций", ради которой команды десять лет назад уходили в MongoDB. При этом вы не теряете:

  • Транзакции — вставка события и обновление счётчика в той же таблице users происходят в одной ACID-транзакции.
  • Связи — колонка payload живёт рядом с обычными реляционными колонками user_id, created_at, и по ним работают обычные внешние ключи и индексы.
  • Один инструмент вместо двух — не нужно поддерживать PostgreSQL для "структурных" данных и отдельно MongoDB для "гибких", с двумя системами бэкапа, мониторинга, прав доступа.

Это не значит, что JSONB — универсальная замена документной базе в любом объёме. При очень большом количестве вложенных JSONB-документов и агрессивной записи GIN-индекс становится дороже в поддержке (вздутие индекса, более медленный VACUUM), и здесь имеет смысл честно сравнить нагрузку на конкретном железе, а не полагаться на общие рассуждения.

Но для подавляющего большинства проектов, где раньше выбор в пользу NoSQL объяснялся "у нас гибкая схема", это перестало быть аргументом: PostgreSQL закрывает сценарий гибкой схемы, оставляя все преимущества реляционной модели там, где данные всё-таки связаны.

ACID — это компромисс, а не бесплатный тормоз

Третий и самый важный технический момент: отсутствие строгих транзакционных гарантий (ACID) в некоторых NoSQL-решениях — это осознанный компромисс ради других свойств (в первую очередь горизонтального масштабирования записи и доступности при сетевых разрывах, согласно теореме CAP), а не бесплатное ускорение, доставшееся "по природе" NoSQL.

Что именно вы теряете, отказываясь от строгих ACID-гарантий:

  • Atomicity на уровне нескольких документов. Классический пример — перевод денег между двумя счетами. В PostgreSQL это одна транзакция:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

Если сервер упадёт между двумя UPDATE, транзакция откатится целиком — денег ниоткуда не пропадёт и не появится. В документной базе без многодокументных транзакций (или с ними, но отключёнными ради производительности) при аналогичном сбое вы рискуете получить состояние, где деньги списаны с одного счёта, но не зачислены на другой — а искать и чинить такие расхождения в проде на порядок дороже, чем сэкономленные миллисекунды на записи.

  • Изоляция и предсказуемость чтения. Многие NoSQL-решения по умолчанию работают в режиме eventual consistency — то есть только что записанные данные могут ещё какое-то время не быть видны при чтении с другого узла. Для ленты новостей это почти незаметно. Для остатка товара на складе или статуса оплаты заказа — это прямой путь к овербукингу и продаже того, чего уже нет.
  • Constraints на уровне СУБД. Внешние ключи, CHECK, UNIQUE в реляционной базе гарантируются самой СУБД при каждой записи. В документной модели аналогичную логику обычно приходится переносить в код приложения — а значит, любой прямой доступ к базе в обход этого кода (миграция, ручной фикс, другой сервис) может нарушить целостность данных незаметно.

Честный вывод здесь такой: если ваша предметная область — финансы, заказы, биллинг, инвентарь, бронирования — то есть везде, где цена рассинхронизации данных выше цены нескольких лишних миллисекунд на запрос, отказ от ACID почти никогда не окупается. Проблемы, которые он создаёт (расхождения в данных, которые обнаруживаются через месяцы в проде, а не сразу на тестах), стоят заметно дороже выигрыша в скорости, который часто вообще не проявляется на реальном объёме нагрузки конкретного проекта.

Как выбирать: чек-лист по форме данных и консистентности

Вместо вопроса "что быстрее — SQL или NoSQL" стоит задавать четыре других вопроса — они и определяют выбор:

  1. Есть ли у данных естественные связи (заказ-товар-пользователь), которые нужно джойнить в большинстве запросов? Если да — реляционная модель ближе к задаче, начинайте с PostgreSQL или MySQL.
  2. Критична ли строгая консистентность (деньги, остатки, статусы заказов)? Если да — нужны ACID-гарантии, и это почти всегда реляционная СУБД либо документная база с явно включёнными многодокументными транзакциями (что снижает часть её преимущества в скорости записи).
  3. Меняется ли схема данных чаще, чем раз в спринт, и это правда неизбежно (а не следствие того, что дизайн предметной области ещё не продуман)? Если да — начните с JSONB-колонки в PostgreSQL, это дешевле по инфраструктуре, чем отдельная документная СУБД, и даёт почти ту же гибкость.
  4. Нужно ли шардировать запись по ключу на десятки узлов уже на старте, а не "когда-нибудь при росте"? Если это подтверждённая необходимость здесь и сейчас (а не запас на гипотетический рост) — тогда стоит рассмотреть NoSQL с шардированием из коробки или Citus/Vitess поверх реляционной СУБД.

Для большинства проектов на старте (SaaS, интернет-магазин, CRM, внутренний сервис) ответы на первые два вопроса — "да", а на последние два — "нет". Это и объясняет, почему PostgreSQL остаётся выбором по умолчанию для новых проектов, а не потому что "SQL лучше NoSQL вообще". Если сомневаетесь, с чего начать конкретно ваш проект, посмотрите более общий разбор в статье как выбрать базу данных для проекта — там разложен более широкий набор критериев, не только скорость.

Если же вы уже начали с MongoDB "по умолчанию" и подозреваете, что данные на самом деле реляционные — миграция возможна, но требует спроектировать схему заново, а не просто перелить документы в таблицы. Здесь пригодится статья про сравнение MongoDB и PostgreSQL для конкретного проекта — в ней разобраны критерии перехода в обе стороны.

А если проблема не в выборе СУБД, а в том, что даже правильно выбранная реляционная база тормозит на конкретных запросах — почти всегда дело в отсутствующих или неправильных индексах, а не в парадигме. Разбор того, как индекс ускоряет запрос и когда наоборот замедляет, закрывает добрую половину таких случаев без миграции на другую СУБД вообще.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Значит ли это, что NoSQL вообще не нужна?

Нет. Для кэшей (Redis), потоков событий, каталогов с по-настоящему разнородными атрибутами и графовых связей документные и специализированные хранилища закрывают задачи, которые реляционная модель решает неудобно. Миф не в существовании этих сценариев, а в переносе вывода на все проекты подряд.

Может ли MongoDB быть быстрее PostgreSQL на моих данных?

Технически да, если ваша нагрузка — это в основном независимая запись документов без связей и без требований к строгой консистентности. Проверяется это не общими рассуждениями, а тестом на реальной схеме и реальном профиле запросов вашего приложения — обобщённые бенчмарки из интернета для конкретного проекта не показательны.

Что выбрать для нового проекта, если непонятно, как вырастут данные?

Начинать с PostgreSQL и JSONB для действительно гибких частей схемы — это даёт ACID-гарантии там, где они важны, и гибкость там, где нужна, без необходимости заранее угадывать архитектуру распределённой системы.

Правда ли, что реляционные базы не масштабируются горизонтально?

Не совсем — партиционирование, репликация с балансировкой чтения и инструменты вроде Citus для PostgreSQL или Vitess для MySQL закрывают горизонтальное масштабирование для многих сценариев. Это требует больше настройки, чем "шардирование из коробки" у некоторых NoSQL, но не делает реляционные СУБД принципиально непригодными для роста.

Есть ли смысл использовать обе парадигмы в одном проекте?

Да, это распространённая практика: PostgreSQL для основных данных со связями и транзакциями, Redis — для кэша и сессий, отдельное хранилище — для логов или полнотекстового поиска. Выбор делается per-задача, а не один раз "на весь проект".

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →