SQL vs NoSQL: выбор

SQL (реляционные БД) хранят данные в таблицах со строгой схемой и поддерживают ACID-транзакции; NoSQL (документные, ключ-значение, колоночные, графовые) жертвуют жёсткостью схемы ради гибкости и горизонтального масштабирования.

Зачем нужно

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

Где используется

  • SQL — финансовые системы, ERP, интернет-магазины (заказы, инвентарь), любые системы с отношениями между сущностями
  • MongoDB — CMS, профили пользователей с переменными атрибутами, прототипы
  • Redis — кеш, сессии, rate-limiting, очереди
  • Elasticsearch — полнотекстовый поиск, логи, аналитика

Основной контент

Сравнительная таблица

Критерий SQL (PostgreSQL) MongoDB Redis
Модель данных Таблицы Документы (BSON/JSON) Ключ-значение
Схема Строгая Гибкая Нет
ACID Полная Частичная (с v4.0) Нет
JOIN Да Через $lookup (медленно) Нет
Масштабирование Вертикальное (Read Replicas) Горизонтальное (Sharding) Горизонтальное (Cluster)
Скорость чтения Средняя Высокая (без JOIN) Очень высокая (in-memory)
Транзакции Да Только в replica set Нет (MULTI/EXEC)
Миграции Обязательны Опциональны

Когда выбирать SQL (PostgreSQL)

Выбирай SQL если:
  ✓ Данные взаимосвязаны (заказы → товары → пользователи)
  ✓ Нужны ACID-транзакции (финансы, инвентарь)
  ✓ Схема стабильна и хорошо известна
  ✓ Нужны сложные запросы (JOIN, агрегация, window functions)
  ✓ Целостность данных критична (внешние ключи)
-- SQL хорошо выражает связанные запросы
SELECT u.name, COUNT(o.id) as order_count, SUM(o.total) as total_spent
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE u.created_at > '2024-01-01'
GROUP BY u.id
HAVING COUNT(o.id) > 5
ORDER BY total_spent DESC;

Когда выбирать MongoDB

Выбирай MongoDB если:
  ✓ Документы с непредсказуемой структурой
  ✓ Часто меняющаяся схема (прототип, стартап)
  ✓ Вложенные данные хранятся вместе (пост + комментарии)
  ✓ Горизонтальное масштабирование с самого начала
  ✗ Нужны сложные JOIN
  ✗ Финансовые данные (строгие транзакции)
// MongoDB хорошо справляется с вложенными документами
{
  _id: ObjectId('...'),
  title: 'Product',
  attributes: {        // разные атрибуты для разных категорий
    color: 'red',
    size: 'XL',
    material: 'cotton'
  },
  reviews: [           // встроенный массив отзывов
    { user: 'Alice', rating: 5, text: '...' }
  ]
}

Polyglot Persistence — несколько БД в одном приложении

Типичная архитектура:

PostgreSQL  ← основные данные (заказы, пользователи, транзакции)
MongoDB     ← контент (статьи, продукты с произвольными полями)
Redis       ← кеш, сессии, rate-limiting
Elasticsearch ← полнотекстовый поиск

Node.js: подключение разных БД

// Один сервис может работать с несколькими БД
const { Pool } = require('pg');        // PostgreSQL — транзакции
const mongoose = require('mongoose');   // MongoDB — контент
const Redis = require('ioredis');       // Redis — кеш

// Правило: кешируй в Redis → читай из MongoDB/PostgreSQL
async function getProduct(id) {
  const cached = await redis.get(`product:${id}`);
  if (cached) return JSON.parse(cached);

  const product = await db('products').where({ id }).first; // PostgreSQL
  await redis.set(`product:${id}`, JSON.stringify(product), 'EX', 300);
  return product;
}

Частые ошибки

  • MongoDB для всего — начать с MongoDB ради простоты, потом обнаружить, что нужны JOIN и транзакции
  • Хранить всё в одной БД — использовать PostgreSQL как очередь задач или как кеш: плохая идея
  • Игнорировать индексы в NoSQL — MongoDB без индексов делает full collection scan; эффект как без индексов в SQL
  • Преждевременный выбор "масштабируемой" NoSQL — 90% стартапов никогда не достигают масштаба, при котором PostgreSQL становится узким местом

Связанные темы

Ресурсы