Шпаргалка по базам данных: Sql vs nosql, индексы, транзакции и репликация

Чтобы выбрать лучший вариант базы данных, начните с требований к связям и транзакциям: для строгой схемы, сложных JOIN и предсказуемой согласованности чаще подходит SQL; для гибких документов, высокой скорости записи и простого горизонтального масштабирования - NoSQL. Дальше уточните стратегию индексов, уровни изоляции и схему репликации под ваши SLA и профиль нагрузки.

Шпаргалка: что важно знать в одну страницу

  • Если нужны сложные связи, отчётность и гарантии транзакций - начинайте с SQL; NoSQL берите под документы/ключ-значение/графы и масштабирование по шардам.
  • Индексы ускоряют чтение, но всегда удорожают запись, память и обслуживание; выбирайте их под реальные запросы и планы выполнения.
  • Транзакции - это не только "есть/нет", а уровни изоляции, конфликтность и стоимость блокировок; шаблоны (outbox, saga) часто важнее выбора движка.
  • Репликация - это компромисс между задержкой, RPO/RTO и сложностью; сначала определите, что важнее: свежесть чтения или доступность при сбоях.
  • Производительность чаще ломают неверные запросы, кардинальность и блокировки, а не "не та база"; сначала профилируйте и исправляйте узкие места.
  • Выбор "лучшего" - это дерево решений: модель данных → транзакционность → индексы → репликация → масштабирование → операционные риски.

Выбор модели данных: реляционные vs документные и графовые

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

Короткое объяснение: SQL выигрывает, когда важны строгая модель и связи; документные NoSQL - когда структура меняется и данные естественно группируются; графовые - когда ключевое действие пользователя/сервиса - обход связей.

Критерии выбора (проверяйте по порядку)

Шпаргалка по базам данных: SQL vs NoSQL, индексы, транзакции, репликация - иллюстрация
  1. Связи и JOIN: много связей N:M и аналитика по связям → SQL; обход связей на глубину (рекомендации, сети) → графовая.
  2. Стабильность схемы: схема стабильна и требует валидации → SQL; поля часто меняются/разные у сущностей → документная.
  3. Транзакции: нужна атомарность на нескольких таблицах/сущностях → SQL; допускаете eventual consistency и "схлопывание" в один документ → NoSQL.
  4. Тип запросов: ad-hoc запросы, агрегации, отчёты → SQL; точечные чтения по ключу/фильтрам → документная/ключ-значение.
  5. Горизонтальное масштабирование: ожидается активный шардинг по ключу → чаще проще в NoSQL, но возможно и в SQL при грамотном дизайне.
  6. Конкурентная запись: частые конфликты при обновлениях одних и тех же строк → подумайте о модели блокировок/версионирования и укрупнении агрегатов.
  7. Операционная зрелость: команда сильнее в SQL-экосистеме и инструментировании → SQL даст меньше сюрпризов; иначе закладывайте время на практику и runbook'и.
  8. Интеграции: BI/ETL, стандартные драйверы, привычный SQL → плюс в пользу SQL даже при "документной" предметке.

Быстрое сравнение SQL и NoSQL на практике

Критерий SQL (реляционные) NoSQL (документные/ключ-значение/графовые) Пример, где часто выигрывает
Модель данных Таблицы, связи, нормализация Документы/ключи/рёбра; денормализация Заказы и платежи (SQL) vs профиль пользователя с разными полями (документы)
Запросы JOIN, оконные функции, сложные агрегации Часто запросы вокруг ключа/документа; граф - обход Отчётность и аналитика в OLTP (SQL) vs лента по ключу (NoSQL)
Согласованность Как правило проще добиться строгой согласованности Часто по умолчанию слабее; зависит от продукта и настроек Инвентарь/остатки (SQL) vs кэш/сессии (NoSQL key-value)
Миграции Явные миграции схемы, строгие контракты Гибче на чтении, но сложнее контролировать "зоопарк" форматов Стабильные домены (SQL) vs быстрые итерации API (документы)
Шардирование Возможно, но часто сложнее и требовательнее к дизайну Обычно одна из сильных сторон Глобальные ленты/события с ключом шарда (NoSQL)

Практический шаг: если вы сейчас на этапе консультация по выбору базы данных SQL или NoSQL, сформулируйте 10-20 "главных" запросов (read/write) и проверьте, как они выглядят в каждой модели: сколько JOIN, насколько естественно ложатся в один документ, где возможны конфликты записи.

Индексы: виды, стоимость и практические правила применения

Проблема: индексы добавляют скорость "в чтение", но незаметно создают долги: рост времени записи, раздувание памяти, сложность обслуживания и неожиданные планы.

Короткое объяснение: индексы выбирают под конкретные фильтры/сортировки и кардинальность. "Настройка индексов в базе данных" почти всегда начинается с EXPLAIN/профилировщика и проверки селективности.

Сравнение вариантов индексации и когда они окупаются

Вариант Кому подходит Плюсы Минусы Когда выбирать
B-tree (по умолчанию в большинстве SQL) OLTP с равенством и диапазонами, сортировки Универсален; хорошо работает для WHERE, ORDER BY, диапазонов Дороже запись; может не помочь при низкой селективности Если есть фильтр по полю и/или сортировка, и поле достаточно селективно
Hash-индекс Точечные запросы по равенству Быстрый lookup по точному совпадению Обычно бесполезен для диапазонов и сортировок; ограничения по функциональности Если почти все запросы вида key = value и нет ORDER BY по этому ключу
Составной (compound) индекс Сервисы с предсказуемыми фильтрами по нескольким полям Может закрывать несколько условий одним индексом; иногда "покрывает" запрос Порядок колонок критичен; риск набрать много похожих индексов Если в запросах часто встречается один и тот же префикс условий (A, затем B)
Покрывающий индекс (include/covering) Чтение "без похода в таблицу" Сильно снижает random I/O и latency на чтении Увеличивает размер индекса и стоимость записи Если запрос читает небольшой набор колонок и выполняется очень часто
Частичный/фильтрованный индекс Большие таблицы с "горячим" подмножеством строк Меньше размер; быстрее обслуживание; лучше фокус на реальных запросах Нужно поддерживать условие; риск "мимо кассы" при изменении запросов Если фильтр почти всегда включает статус/флаг (например, active = true)
Полнотекстовый индекс Поиск по тексту, морфология, релевантность Заметно лучше, чем LIKE %...% по большим текстам Особое обслуживание и настройки; не заменяет специализированный поиск Если нужен быстрый поиск по словам/фразам в описаниях, комментариях

Практические правила, чтобы индексы помогали, а не мешали

  1. Начинайте с запроса и плана выполнения: фиксируйте реальный SQL и параметры, а не "как будто".
  2. Проверяйте селективность: индекс по полю с одинаковыми значениями часто не ускорит фильтр.
  3. Не плодите похожие составные индексы: один удачный индекс может заменить 2-3 плохих.
  4. Помните про запись: каждая вставка/обновление обновляет индексы; для write-heavy систем индексируйте минимально.
  5. Регулярно пересматривайте: индексы устаревают вместе с продуктом и меняющимися запросами.

Где учиться: если вы выбираете обучение базам данных SQL или курсы SQL и NoSQL, берите программу, где есть разбор EXPLAIN/ANALYZE, селективности и проектирования составных индексов на реальных схемах, а не только синтаксис SELECT.

Транзакции и согласованность: уровни, ограничения и шаблоны

Проблема: "нужны транзакции" часто означает разные вещи: атомарность, отсутствие грязных чтений, защита от потерянных обновлений, или просто идемпотентность.

Короткое объяснение: выбирайте не абстрактный ACID/BASE, а конкретные гарантии на сценарии. В SQL чаще проще включить строгую изоляцию, но она может бить по конкуренции. В NoSQL чаще придётся проектировать агрегаты, идемпотентность и компенсирующие операции.

Сценарии "если..., то..." для выбора подхода

  • Если нужно списание денег и изменение нескольких сущностей (баланс, проводка, заказ) то берите SQL-транзакцию с явными ограничениями (FK/UNIQUE) и обработкой ретраев при конфликте.
  • Если вы можете свести запись к одному агрегату (например, заказ хранится одним документом) то документная модель с атомарным обновлением документа уменьшит потребность в кросс-объектных транзакциях.
  • Если бизнес-процесс длинный и затрагивает несколько сервисов то используйте saga (оркестрация/хореография) и компенсирующие действия, независимо от того SQL или NoSQL внутри.
  • Если важна гарантия "событие не потеряется" при публикации в очередь то применяйте outbox-паттерн (таблица/коллекция outbox + фоновые публикации) вместо попыток "двухфазно" связать БД и брокер.
  • Если конфликты обновлений часты (много параллельных апдейтов одной записи) то добавляйте оптимистическую блокировку (версия/etag) и повтор операции, а не только повышайте уровень изоляции.

Репликация и отказоустойчивость: топологии, задержки и выбор стратегии

Проблема: "сделать репликацию" без целей приводит к системе, которая либо медленно пишет, либо читает устаревшее, либо тяжело восстанавливается.

Короткое объяснение: репликация - это выбор компромисса между доступностью, свежестью чтения и сложностью фейловера. "Настройка репликации базы данных" должна начинаться с требований к восстановлению и допустимой потере данных.

Быстрый алгоритм выбора стратегии (проверьте 6 пунктов)

  1. Определите, что для вас критичнее: нулевая/минимальная потеря данных или максимальная доступность при сетевых проблемах.
  2. Решите, допустимы ли устаревшие чтения: если нет - читайте с лидера или используйте подтверждённые чтения (read-after-write) там, где это поддерживается.
  3. Выберите топологию: один лидер + реплики (проще) или несколько лидеров (сложнее, риск конфликтов), или шарды с локальными лидерами.
  4. Определите модель подтверждений записи: ждать ли реплики при коммите (строже, но медленнее) или писать на лидера и догонять реплики асинхронно.
  5. Продумайте фейловер: автоматический или ручной; кто "истина" при разделении сети; как предотвратить split-brain.
  6. Согласуйте бэкапы и восстановление: репликация не заменяет бэкап; проверяйте восстановление на стенде по runbook'у.

Производительность в бою: планы запросов, блокировки и горизонтальное масштабирование

Проблема: выбор SQL/NoSQL часто делается "по моде", а деградации появляются из-за запросов, кардинальности, блокировок и неверного шардинга.

Короткое объяснение: сначала смотрите планы, метрики и конкуренцию, затем меняйте схему/индексы/репликацию. Масштабирование "добавим ноды" работает только при правильном ключе распределения и контроле горячих точек.

Частые ошибки, из-за которых база начинает тормозить

  • Индексы добавлены "на всякий случай", а write path стал дороже и выросли задержки коммита.
  • Нет контроля планов: запросы меняются, статистика устаревает, план внезапно становится хуже.
  • Фильтрация и сортировка не совпадают с индексом (не тот порядок в составном индексе, нет префикса).
  • JOIN по неиндексированным ключам или по выражениям (функции, касты), что ломает использование индекса.
  • Транзакции держат блокировки слишком долго (внутри - сетевые вызовы, сложная логика), накапливаются очереди ожидания.
  • N+1 запрос и "чаты" с БД вместо пакетирования.
  • Шард-ключ выбран по низкой кардинальности (горячие шарды) или меняется со временем (миграции становятся дорогими).
  • Чтение с реплик без понимания лагов: пользователь "только что записал" и "не видит" результат.
  • Нет лимитов и пагинации: тяжёлые запросы забивают пул соединений и I/O.

Дерево решений: как выбрать базу и конфигурацию для конкретной задачи

Проблема: хочется "лучший вариант", но в реальности "лучший" - это тот, который минимизирует риски именно вашего профиля чтения/записи и требований к согласованности.

Мини-дерево решений (да/нет) для первичного выбора

  1. Нужны сложные JOIN, отчёты, строгая схема и ограничения целостности?
    • Да → начинайте с SQL.
    • Нет → идём дальше.
  2. Данные естественно укладываются в "агрегаты" (один запрос читает/пишет один объект целиком)?
    • Да → документная NoSQL или key-value (если всё вокруг ключа).
    • Нет → идём дальше.
  3. Ключевая операция - обход связей на несколько шагов (рекомендации, граф зависимостей, социальные связи)?
    • Да → графовая БД (или специализированный графовый слой).
    • Нет → идём дальше.
  4. Нужна атомарность изменений сразу в нескольких сущностях без сложных компенсирующих сценариев?
    • Да → SQL с транзакциями и продуманной изоляцией.
    • Нет → можно проектировать eventual consistency + outbox/saga.
  5. Ожидается агрессивное горизонтальное масштабирование по понятному ключу (tenant_id, user_id, region)?
    • Да → выбирайте движок/схему с понятным шардированием и заранее тестируйте горячие ключи.
    • Нет → проще и дешевле поддерживать одну SQL-инсталляцию с репликами чтения.
  6. Команда готова поддерживать более сложную операционку (шарды, консистентность, конфликты, миграции форматов)?
    • Да → NoSQL становится реальным кандидатом.
    • Нет → SQL часто даст быстрее предсказуемый результат.

Итоговая рекомендация обычно выглядит так: для платёжного ядра, заказов, учёта и отчётности чаще "лучший" - SQL с аккуратной индексацией и понятной репликацией; для профилей, событий, кэшей и высоконагруженных ключевых чтений - NoSQL с продуманным ключом шарда; для задач, где ценность в связях, - графовая модель. Если сомневаетесь, начните с прототипа на 10-20 ключевых запросов и зафиксируйте критерии успеха.

Распространённые сомнения и короткие решения

Можно ли "взять NoSQL и забыть про схему"?

Нет: схема просто становится неявной и переезжает в код и данные. Зафиксируйте контракт на уровне API и валидации, иначе вы получите несовместимые форматы документов.

SQL не масштабируется горизонтально - это правда?

Масштабируется, но цена выше: шардирование, распределённые транзакции, операционная сложность. Если профиль нагрузки шардируется по ключу, сравните стоимость реализации в SQL и в NoSQL на ваших сценариях.

Сколько индексов "нормально" держать на таблице?

Универсального числа нет. Критерий простой: каждый индекс должен обслуживать конкретные частые запросы и окупать стоимость записи и обслуживания.

Какая изоляция транзакций "лучше" для OLTP?

"Лучше" та, которая предотвращает нужные вам аномалии при приемлемых блокировках. Начинайте с более мягкой изоляции, добавляйте ретраи и усиливайте изоляцию точечно для критичных операций.

Репликация заменяет бэкапы?

Шпаргалка по базам данных: SQL vs NoSQL, индексы, транзакции, репликация - иллюстрация

Нет. Репликация копирует и логические ошибки (удаления, повреждения данных), поэтому бэкапы и проверка восстановления обязательны.

Почему чтение с реплики иногда не видит только что записанные данные?

Из-за лага репликации и асинхронного применения изменений. Для критичных экранов используйте чтение с лидера или гарантии read-after-write, если они доступны.

Как понять, что пора просить помощь, а не "тюнить ещё неделю"?

Если вы упёрлись в блокировки/планы и не можете связать метрики с конкретными запросами, нужна диагностика с профилировщиком и логами. В этот момент полезна точечная консультация по выбору базы данных SQL или NoSQL и ревизия схемы запросов.

Прокрутить вверх