Война SQL против NoSQL окончилась, как заканчиваются все взрослые споры: победили сценарии. Реляционные базы, хранящие данные в таблицах со связями, и нереляционные хранилища с документами, ключами и графами перестали быть лагерями с знамёнами и стали инструментами с областями применения. Вопрос профессионала звучит не "что лучше", а "какие данные, какие операции, какая согласованность и какой рост" - и ответ на него у каждого проекта собственный. Ниже разобрано то, как ответы складываются в осмысленный выбор, без рекламы и без страха перед терминами, которых можно не пугаться.
Оговорка о терминах сэкономит дальше половину путаницы. Нереляционное семейство объединяет принципиально разные машины: документные хранилища, ключ-значение, колоночные и графовые базы, поисковые движки и очереди. Говорить "NoSQL" как об одном выборе инструментов - всё равно что выбирать между "транспортом" и "велосипедом", не уточняя, куда и сколько нужно перевезти. Поэтому настоящий спор происходит не между лагерями, а внутри конкретного списка требований.
Реляционная модель сильна в связях и транзакциях
Ядро реляционного подхода - таблицы со строгой схемой и связями между ними. Заказ ссылается на покупателя, позиция заказа - на товар, и целостность этих связей гарантирует сама база: невозможно сослаться на несуществующий товар, невозможно удалить покупателя с живыми заказами. Эта строгость оплачивается дисциплиной схемы - изменение структуры требует миграции, - но взамен даёт данные, которым можно доверять без проверки каждого отношения вручную.
Транзакции - вторая опора: группа операций выполняется целиком или не выполняется никак. Перевод со счёта на счёт, списание остатка при заказе, обновление связанных таблиц при оплате - сценарии, где половинное состояние означает потерянные деньги, а атомарность является не удобством, а определением корректности:
BEGIN;
UPDATE accounts SET balance = balance - 500 WHERE id = 1;
UPDATE accounts SET balance = balance + 500 WHERE id = 2;
INSERT INTO transfers (from_id, to_id, amount) VALUES (1, 2, 500);
COMMIT;
Сила реляционной модели проявляется в запросах со связями: отчёт по покупателям с их заказами, позициями и статусами собирается одним выражением с соединениями, и соединяются миллионы строк быстрее, чем любой прикладной код. Любая система, чьи данные по природе сетчатые - бухгалтерия, учёт, каталог со связями, - живёт на реляционной базе естественно.
Зрелость реляционной работы измеряется индексами: почти любой сценарий медленного запроса лечится правильным индексом, и обратное тоже верно - отсутствующий индекс на таблице в миллионы строк не лечится ничем кроме него. Профессиональная дисциплина связана с планами запросов: медленный запрос не оптимизируется вслепую, а разбирается по плану, где видно, что база читает всю таблицу там, где должен работать индекс. Индекс проектируется под запрос, а не наоборот: сначала реальные запросы, потом индексы под них, потому что лишние индексы замедляют запись так же честно, как нужные ускоряют чтение.
Слабости той же модели известны: строгая схема замедляет эксперименты, горизонтальное масштабирование на множество машин исторически сложнее, и типичный рост пишущей нагрузки упирается в одну машину. Эти слабости - не приговор, а плата, и разумность платы проверяется сценарием.
Отдельно про миграции: строгая схема означает, что изменение модели - событие с историей. Миграции версионируются, применяются по порядку и откатываются, и через два года по файлам миграций читается вся эволюция данных проекта. В проектах без схемы эволюция форм живёт в коде и в памяти ветеранов, и это различие ощущается в первую очередь при расследовании инцидентов.
Документные хранилища сильны в скорости разработки и бесформенных объектах
Документная база хранит объекты целиком: запись о пользователе с адресом, настройками и историей лежит одним документом, и чтение профиля - один запрос без соединений. Для сценариев "читай объект целиком по ключу" документное хранилище быстрее и удобнее: нет схемы, нет миграций под каждое поле, новые атрибуты просто появляются в новых документах:
db.users.insertOne({
login: "roman",
address: { city: "Тверь", street: "Мира" },
settings: { theme: "dark", notifications: { email: true, push: false } },
tags: ["pro", "beta-tester"]
});
Скорость разработки - главный аргумент документных хранилищ в проектах с меняющейся моделью: прототипы, продуктовые эксперименты, быстро меняющиеся конфигурации. Отсутствие схемы ускоряет первые месяцы, и зрелые команды честно отмечают обратную сторону: без централизованной схемы форма данных держится на дисциплине кода, и через год в коллекции живут документы с пятью вариантами одного поля.
Проектировщик документного слоя учитывает и размер: документы читаются целиком, и вложенный массив истории в одном документе однажды переваливает за разумный предел чтения. Гигиеническое правило документных хранилищ простое: всё, что растёт без предела, выносится в отдельную коллекцию и не нагружает каждое чтение.
Связи - ахиллесова пята документов: запрос "все заказы покупателей из города с суммами по категориям" собирается прикладным кодом из нескольких обращений, либо дублированием данных ради читаемости. Дублирование - осознанный компромисс: быстрое чтение оплачивается синхронизацией копий при изменениях, и сложность переезжает из базы в код.
Дисциплина документного слоя при этом не капитуляция, а здравый смысл: скорость безсхемности сохраняется, а хаос безсхемности ограничивается тремя привычками - валидацией на входе, соглашениями имён полей и миграционными скриптами для переименований. Команда с этими привычками получает скорость без хаоса, и документная база честно показывает сильные стороны вместо случайных документов.
Ключ-значение и специализированные хранилища закрывают точечные сценарии
Семейство ключ-значение отвечает на два вопроса: положить по ключу и достать по ключу, максимально быстро. Кэш сессий, счётчики, лимиты, результаты тяжёлых вычислений - сценарии, где данные просты, а цена микросекунд реальна. Ставить кэш на реляционную базу - значит платить за транзакции, которых сценарий не требует, и кэширующий слой в веб-проектах почти всегда живёт отдельно от основной базы.
Поисковые движки отвечают на полнотекстовый поиск: релевантный поиск по словам, морфологии, опечаткам - отдельная инженерная дисциплина, и попытки воспроизвести её на регулярных таблицах на регулярных таблицах вырождается в нечитаемые запросы. Графовые базы отвечают на связи как на главный герой: социальные связи, маршруты, цепочки рекомендаций, где глубина обхода - суть запроса.
Очереди и потоки сообщений - отдельный вид хранилищ, часто неописываемый в споре про базы, но незаметно ставший обязательным слоем веб-систем: фоновые задачи, шина событий, буфер между быстрым запросом и медленной работой. Профессиональная архитектура данных собирается из нескольких специализированных слоёв, и спор "одна база на всё" остался в прошлом десятилетии.
Графовые хранилища заслуживают отдельного уважения за сценарии, которые на обычных базах превращаются в многослойные обходы: цепочка друзей друзей, путь по сети дорог, цепочка зависимостей. Запрос глубины три на реляционной базе - это два соединения; глубина пять с переменной структурой - уже рекурсия в коде, а в графе - одна строка обхода. Выбор хранилища по форме запроса, а не по форме хранения, - признак зрелого проектировщика.
Согласованность и масштабирование весят больше хайповых таблиц сравнения
Настоящий выбор проходит по двум осям, о которых вспоминают позже всего. Согласованность: как быстро и насколько гарантированно читатели видят изменения. Транзакционная строгость реляционных баз - линейный порядок операций; распределённые хранилища часто дают согласованность в конечном счёте - обновление доезжает через мгновения, и сценарий обязан это выдерживать. Корзина терпит, банковский остаток - нет.
Масштабирование: реляционная база растёт вертикально и читателями, реплики разгружают чтение; шардирование письма - операция серьёзная и осознанная. Документные и ключ-значные семейства исторически выросли из потребности горизонтального роста и умеют его проще, но платят гибкостью запросов по связям. Выбор "на вырост" по шкалированию без реального прогноза нагрузки - типовая ошибка: проектируется система под миллионы пользователей, которые не приходят, а плата за распределённость выплачивается с первого дня.
Зрелая процедура выбора выглядит скромно: перечень сценариев чтения и записи с частотами, требования согласованности по каждому, прогноз роста на год. Подавляющее число веб-проектов после такой процедуры обнаруживает реляционную базу как ядро с кэш-слоем и очередью по краям - и это не отсталость, а честный расчёт.
Повседневная реальность больших проектов смешивает подходы без чувства вины
Крупные системы давно перестали выбирать одну базу на всё. Ядро учёта живёт в реляционной базе, потому что деньги и связи. Профили и настройки - в документной, потому что форма меняется. Сессии и кэш - в ключ-значении, потому что микросекунды. Поиск - в поисковом движке, потому что релевантность. Аналитика - в колоночном хранилище, потому что агрегаты. Каждый слой выбран по своему сценарию, и вместе они образуют архитектуру, где база данных - не решение, а решения.
Смешение при этом не означает анархии: границы слоёв описаны явно, у каждого типа данных есть дом, и перемещение между слоями - осознанная миграция, а не еженедельное переселение. Практический паттерн связывания - события: изменение в ядре публикуется, подписчики обновляют свои проекции в документных и поисковых слоях, и читатели получают быстрые копии без потери истины в основной базе.
Команда при смешанной архитектуре обязана владеть дисциплиной данных: где истина, где копии, как чинятся расхождения. Без этой дисциплины полиглотная база превращается в вавилон, где одни и те же данные отвечают по-разному, и пользователи первыми замечают рассинхронизацию.
Инструмент такой дисциплины - документ данных: для каждой сущности описан дом, копии, события обновления и правила чтения. Полстраницы на сущность, и смешанная система перестаёт быть вавилоном и становится картой, по которой новый разработчик за полчаса понимает, где лежит истина и почему она лежит именно там. Карта таких документов и есть настоящий архитектурный артефакт смешанной системы.
Практический выбор сводится к честному списку вопросов
Процедура выбора, собранная из практики, сжимается в короткий список:
- данные по природе табличные со связями или бесформенные объекты;
- операции требуют транзакционной строгости или терпят согласованность в конечном счёте;
- чтение целых объектов по ключу или запросы с соединениями и фильтрами;
- прогноз роста нагрузки горизонтален и доказан или умозрителен;
- команда умеет администрировать выбранную технологию на живых инцидентах;
- для каждого типа данных назван его слой и его дом;
- цена смешанной архитектуры - дисциплина границ - честно принята.
Последний пункт списка - самый недооценённый: технологии различаются меньше, чем различается жизнь рядом с ними: эксплуатация, настройка, восстановление после сбоев и поиск причин в три часа ночи. База, которой команда владеет, обыгрывает базу модную, но незнакомую, на дистанции любого проекта. SQL и NoSQL в итоге - не два лагеря, а полка инструментов, и профессионализм измеряется не выбором стороны, а точностью, с которой инструмент прикладывается к сценарию. Проекты, которые выбирают так, получают скучную, предсказуемую и дешёвую в сопровождении систему данных - самую роскошную архитектуру из возможных.