Три года назад мы запускали сервис, где схема данных менялась буквально каждую неделю: появлялись новые поля, эксперименты с тарифами, разные типы заказов. Классический аргумент в пользу MongoDB звучал убедительно — никаких миграций, просто кладём документ и живём. Через год мы переписывали половину бэкенда на PostgreSQL и до сих пор вспоминаю тот рефакторинг с лёгкой дрожью. Расскажу честно, где я был неправ, а где виноват инструмент.
Соблазн был сильный и вполне рациональный. Молодая команда, никакого DBA, продукт ещё ищет себя. Документная модель позволяла не думать о нормализации: заказ лежит одним объектом, вложенные позиции, адрес доставки, история статусов — всё внутри. Тесты писались быстро, фичи выкатывались за пару дней, и первые месяцы это действительно работало как реклама. Проблемы начались не с моделью данных, а с вопросами, которые к ней начали задавать.
Первым пришёл бизнес и попросил отчёт по выручке в разрезе категорий, регионов и месяцев. В мире документов это означало либо несколько проходов агрегаций, либо копию данных в отдельное аналитическое хранилище. Вторым пришла бухгалтерия и попросила гарантии, что списание денег и создание заказа происходят вместе. И вот тут выяснилось, что транзакции между несколькими коллекциями — это не то, на что стоит рассчитывать, а целостность ссылок мы уже год поддерживаем руками в коде приложения. Код поддержки разросся до размеров самого продукта.
Но справедливости ради: PostgreSQL — тоже не серебряная пуля, и я не хочу выглядеть адептом. Если у вас десятки тысяч записей в секунду и данные действительно слабо связаны, реляционная модель начнёт мешать. Однако за последние годы я всё реже слышу аргумент «нам нужна гибкость схемы». Потому что в PostgreSQL есть JSONB: вы храните документ как есть, индексируете его поля, делаете выборки и при этом остаётесь внутри транзакций, JOIN и обычного SQL. В большинстве проектов этого хватало с запасом.
Есть сценарии, где MongoDB чувствует себя на своём месте, и я их честно признаю. Логи и события, поток телеметрии, каталоги, где товары настолько разные, что общая схема превращается в свалку пустых колонок, кэширование результатов внешних API. Шардирование из коробки, горизонтальное масштабирование записи и денормализация как норма, а не как компромисс. Если ваша задача выглядит так — Mongo не просто уместна, она удобнее. Просто это не про типичный CRUD-сервис с деньгами и отчётами.
Мой чек-лист перед выбором теперь выглядит так. Нужны ли мне транзакции и связи между сущностями — если да, начинаю с PostgreSQL. Что со аналитикой через полгода: если ответ «не знаю, но спросят», реляционная база дешевле. Кто будет это эксплуатировать в три ночи — если нет выделенного DBA, я предпочту технологию, про которую любой бэкендер знает, как делать бэкап. Насколько реально неоднородны данные — если разница в пяти полях, это не повод уходить в документы. И последний вопрос: сколько кода на поддержание целостности я готов писать сам.
Что бы я сделал иначе? Начал бы с PostgreSQL по умолчанию, а MongoDB добавлял бы позже и точечно — как специализированное хранилище для конкретного типа данных, рядом с основной базой, а не вместо неё. Миграция «туда» почти всегда дешевле и спокойнее, чем миграция «обратно», когда продукт уже на пользователях. И да, я перестал верить фразе «схема у нас всё равно гибкая»: схема есть всегда, просто в одном случае её описывает база, а в другом — разрозненные куски кода и договорённости в голове разработчика, ушедшего в другой проект.
А теперь интересно ваше мнение, коллеги. Кто переезжал между базами в реальном продакшене — что стало последней каплей, и что вы выбрали в итоге? И есть ли у вас проекты, где MongoDB держится годами и не вызывает ни малейшего желания всё переписать? Делитесь историями, у нас тут как раз тот случай, когда чужой опыт экономит чужой год жизни.
Соблазн был сильный и вполне рациональный. Молодая команда, никакого DBA, продукт ещё ищет себя. Документная модель позволяла не думать о нормализации: заказ лежит одним объектом, вложенные позиции, адрес доставки, история статусов — всё внутри. Тесты писались быстро, фичи выкатывались за пару дней, и первые месяцы это действительно работало как реклама. Проблемы начались не с моделью данных, а с вопросами, которые к ней начали задавать.
Первым пришёл бизнес и попросил отчёт по выручке в разрезе категорий, регионов и месяцев. В мире документов это означало либо несколько проходов агрегаций, либо копию данных в отдельное аналитическое хранилище. Вторым пришла бухгалтерия и попросила гарантии, что списание денег и создание заказа происходят вместе. И вот тут выяснилось, что транзакции между несколькими коллекциями — это не то, на что стоит рассчитывать, а целостность ссылок мы уже год поддерживаем руками в коде приложения. Код поддержки разросся до размеров самого продукта.
Но справедливости ради: PostgreSQL — тоже не серебряная пуля, и я не хочу выглядеть адептом. Если у вас десятки тысяч записей в секунду и данные действительно слабо связаны, реляционная модель начнёт мешать. Однако за последние годы я всё реже слышу аргумент «нам нужна гибкость схемы». Потому что в PostgreSQL есть JSONB: вы храните документ как есть, индексируете его поля, делаете выборки и при этом остаётесь внутри транзакций, JOIN и обычного SQL. В большинстве проектов этого хватало с запасом.
Есть сценарии, где MongoDB чувствует себя на своём месте, и я их честно признаю. Логи и события, поток телеметрии, каталоги, где товары настолько разные, что общая схема превращается в свалку пустых колонок, кэширование результатов внешних API. Шардирование из коробки, горизонтальное масштабирование записи и денормализация как норма, а не как компромисс. Если ваша задача выглядит так — Mongo не просто уместна, она удобнее. Просто это не про типичный CRUD-сервис с деньгами и отчётами.
Мой чек-лист перед выбором теперь выглядит так. Нужны ли мне транзакции и связи между сущностями — если да, начинаю с PostgreSQL. Что со аналитикой через полгода: если ответ «не знаю, но спросят», реляционная база дешевле. Кто будет это эксплуатировать в три ночи — если нет выделенного DBA, я предпочту технологию, про которую любой бэкендер знает, как делать бэкап. Насколько реально неоднородны данные — если разница в пяти полях, это не повод уходить в документы. И последний вопрос: сколько кода на поддержание целостности я готов писать сам.
Что бы я сделал иначе? Начал бы с PostgreSQL по умолчанию, а MongoDB добавлял бы позже и точечно — как специализированное хранилище для конкретного типа данных, рядом с основной базой, а не вместо неё. Миграция «туда» почти всегда дешевле и спокойнее, чем миграция «обратно», когда продукт уже на пользователях. И да, я перестал верить фразе «схема у нас всё равно гибкая»: схема есть всегда, просто в одном случае её описывает база, а в другом — разрозненные куски кода и договорённости в голове разработчика, ушедшего в другой проект.
А теперь интересно ваше мнение, коллеги. Кто переезжал между базами в реальном продакшене — что стало последней каплей, и что вы выбрали в итоге? И есть ли у вас проекты, где MongoDB держится годами и не вызывает ни малейшего желания всё переписать? Делитесь историями, у нас тут как раз тот случай, когда чужой опыт экономит чужой год жизни.