За свою карьеру я дважды попадал в одну и ту же ловушку с выбором базы данных, и оба раза это стоило команде нескольких месяцев переписывания кода. Поэтому теперь, когда ко мне приходят с вопросом, что взять — реляционную базу или что-то из мира NoSQL, я сначала задаю не технический вопрос, а продуктовый: какие данные ты хранишь и какие вопросы собираешься им задавать через год? Звучит банально, но именно на этом этапе ломается большинство решений.
Первый мой опыт был классическим. Мы делали сервис заказов и я, вдохновлённый статьями о гибкости и горизонтальном масштабировании, выбрал документную базу. Хранили заказы, пользователей, платежи и статусы доставки в отдельных коллекциях, связанных идентификаторами. Первые полгода всё летало: схема менялась на ходу, новые поля добавлялись без миграций, разработка шла быстро. А потом пришёл запрос от бизнеса — отчёт по выручке с разбивкой по городам, категориям и месяцам. Я написал этот отчёт на языке запросов примерно так же, как писал бы на ассемблере. Пришлось выгружать данные в реляционную базу и считать там. Это был первый звоночек, который я, к сожалению, проигнорировал.
Второй проект я уже начинал с PostgreSQL, но не потому, что он модный, а потому что данные были честно реляционными: счета, транзакции, права доступа, аудит. И тут случилось открытие, которое я советую проверить каждому: современные реляционные базы давно перестали быть только таблицами. Колонка типа JSONB дала нам всю гибкость документной модели там, где она реально нужна, а транзакции, внешние ключи и оконные функции остались под рукой. Мы не выбирали между удобством и надёжностью — мы получили и то, и другое.
Теперь про критерии выбора, которые я сформулировал для себя уже после всех шишек. Первое: есть ли у данных жёсткие связи и нужны ли вам транзакции на несколько сущностей одновременно. Если вы переводите деньги, меняете баланс, списываете товар со склада — вам нужен SQL, и спорить тут не о чем. Второе: нужны ли вам аналитические и произвольные запросы от бизнеса. Любая система рано или поздно обрастает отчётами и выборками, и если база не умеет соединять данные гибко, вы будете строить поверх неё ещё одну систему. Третье: какая у вас честная нагрузка на запись и чтение. В большинстве внутренних и корпоративных проектов она измеряется сотнями запросов в секунду, а это для SQL абсолютно комфортный режим.
Отдельно скажу про миф о масштабировании, из-за которого люди чаще всего и уходят в NoSQL. Мне ни разу в жизни не встречался проект, которому горизонтальное шардирование понадобилось бы на первом году. Зато я видел десятки проектов, где команда выбрала неудобную базу под гипотетические миллионы пользователей, а получила реальные проблемы с консистентностью, дублированием данных и ручной синхронизацией. Масштабирование — это задача, которую решают тогда, когда она появилась, а не заранее ценой повседневных неудобств всей команды. Если вы упёрлись в потолок, это, как правило, вопрос индексов, кэша, реплик и архитектуры запросов, а не смены парадигмы хранения.
Когда же NoSQL действительно уместен? Я честно использую его в трёх случаях: когда структура данных объективно неструктурирована или меняется каждый день, когда нужен экстремально быстрый доступ по ключу с простыми моделями и огромным объёмом, и когда мы говорим про графовые связи, которые на SQL даются тяжело. Например, кэш сессий, лента событий, метрики, документы произвольной формы — тут документные и ключ-значение базы прекрасны. Проблема начинается ровно в тот момент, когда в такую базу заезжает бухгалтерия, потому что так было быстрее стартовать.
Мой практический совет читателям звучит так. Начните с честного списка сущностей и связей между ними — если связей больше, чем пара, по умолчанию берите реляционную базу, она простит вам почти любую ошибку проектирования. Проверьте, не закрывает ли нужную гибкость JSON-колонка, прежде чем тащить в проект второй движок. Посчитайте, сколько разных баз ваша команда способна поддерживать в продакшене без боли, потому что каждый лишний движок — это бэкапы, мониторинг, обновления и дежурства. И обязательно опишите заранее два-три главных сценария запросов, которые придут от бизнеса — именно они, а не презентации вендоров, покажут, где вы будете страдать через год.
Главное, что я вынес из двух переписываний: база данных — это не выбор технологии, а выбор будущей боли. Можно взять модный движок и год радоваться коротким срокам, а потом год переписывать отчёты. А можно взять скучный проверенный инструмент и просто заниматься продуктом. Я выбрал второе и ни разу не пожалел. А расскажите, был у вас опыт, когда выбранная база оказалась не той — и что именно заставило вас это осознать: отчёты, транзакции, нагрузка или что-то совсем неожиданное?
Первый мой опыт был классическим. Мы делали сервис заказов и я, вдохновлённый статьями о гибкости и горизонтальном масштабировании, выбрал документную базу. Хранили заказы, пользователей, платежи и статусы доставки в отдельных коллекциях, связанных идентификаторами. Первые полгода всё летало: схема менялась на ходу, новые поля добавлялись без миграций, разработка шла быстро. А потом пришёл запрос от бизнеса — отчёт по выручке с разбивкой по городам, категориям и месяцам. Я написал этот отчёт на языке запросов примерно так же, как писал бы на ассемблере. Пришлось выгружать данные в реляционную базу и считать там. Это был первый звоночек, который я, к сожалению, проигнорировал.
Второй проект я уже начинал с PostgreSQL, но не потому, что он модный, а потому что данные были честно реляционными: счета, транзакции, права доступа, аудит. И тут случилось открытие, которое я советую проверить каждому: современные реляционные базы давно перестали быть только таблицами. Колонка типа JSONB дала нам всю гибкость документной модели там, где она реально нужна, а транзакции, внешние ключи и оконные функции остались под рукой. Мы не выбирали между удобством и надёжностью — мы получили и то, и другое.
Теперь про критерии выбора, которые я сформулировал для себя уже после всех шишек. Первое: есть ли у данных жёсткие связи и нужны ли вам транзакции на несколько сущностей одновременно. Если вы переводите деньги, меняете баланс, списываете товар со склада — вам нужен SQL, и спорить тут не о чем. Второе: нужны ли вам аналитические и произвольные запросы от бизнеса. Любая система рано или поздно обрастает отчётами и выборками, и если база не умеет соединять данные гибко, вы будете строить поверх неё ещё одну систему. Третье: какая у вас честная нагрузка на запись и чтение. В большинстве внутренних и корпоративных проектов она измеряется сотнями запросов в секунду, а это для SQL абсолютно комфортный режим.
Отдельно скажу про миф о масштабировании, из-за которого люди чаще всего и уходят в NoSQL. Мне ни разу в жизни не встречался проект, которому горизонтальное шардирование понадобилось бы на первом году. Зато я видел десятки проектов, где команда выбрала неудобную базу под гипотетические миллионы пользователей, а получила реальные проблемы с консистентностью, дублированием данных и ручной синхронизацией. Масштабирование — это задача, которую решают тогда, когда она появилась, а не заранее ценой повседневных неудобств всей команды. Если вы упёрлись в потолок, это, как правило, вопрос индексов, кэша, реплик и архитектуры запросов, а не смены парадигмы хранения.
Когда же NoSQL действительно уместен? Я честно использую его в трёх случаях: когда структура данных объективно неструктурирована или меняется каждый день, когда нужен экстремально быстрый доступ по ключу с простыми моделями и огромным объёмом, и когда мы говорим про графовые связи, которые на SQL даются тяжело. Например, кэш сессий, лента событий, метрики, документы произвольной формы — тут документные и ключ-значение базы прекрасны. Проблема начинается ровно в тот момент, когда в такую базу заезжает бухгалтерия, потому что так было быстрее стартовать.
Мой практический совет читателям звучит так. Начните с честного списка сущностей и связей между ними — если связей больше, чем пара, по умолчанию берите реляционную базу, она простит вам почти любую ошибку проектирования. Проверьте, не закрывает ли нужную гибкость JSON-колонка, прежде чем тащить в проект второй движок. Посчитайте, сколько разных баз ваша команда способна поддерживать в продакшене без боли, потому что каждый лишний движок — это бэкапы, мониторинг, обновления и дежурства. И обязательно опишите заранее два-три главных сценария запросов, которые придут от бизнеса — именно они, а не презентации вендоров, покажут, где вы будете страдать через год.
Главное, что я вынес из двух переписываний: база данных — это не выбор технологии, а выбор будущей боли. Можно взять модный движок и год радоваться коротким срокам, а потом год переписывать отчёты. А можно взять скучный проверенный инструмент и просто заниматься продуктом. Я выбрал второе и ни разу не пожалел. А расскажите, был у вас опыт, когда выбранная база оказалась не той — и что именно заставило вас это осознать: отчёты, транзакции, нагрузка или что-то совсем неожиданное?