От переводчика: Недавно презентовал на Хабре один проект, в котором использовал MySQL. Многие пользователи удивлялись, почему я не использую NoSQL для моих задач, и настоятельно порекомендовали переходить на нереляционные базы данных. Сегодня я наткнулся на эту статью, которая отлично объясняет, почему я “боюсь” NoSQL.
Должен признаться, что долго думал над тем стоит ли писать эссе о базах данных, потому что трогать эту тему всё равно, что открыть банку с червяками (в оригинале – “opening a can of worms” – английская идиома; можно интерпретировать как “Холивар” – прим. перев.). Во-первых, многое было написано до меня, а во-вторых, тема слишком сложна, что бы делать какие-либо выводы из личного опыта.
Последние две недели, однако, заставили меня понять, что я больше никогда не начну проект на основе MongoDB или любой другой нереляционной базы данных (НРДБ) в качестве первичного хранилища данных. Обратите внимание – я сказал “начну”. Я не говорю, что больше никогда не буду использовать MongoDB как таковую.
Прежде чем я начну объясняться, сделаю отступление, чтобы убедиться, что мы с вами на одной волне. Во-первых, мой основной опыт работы с нереляционными хранилищами данных сводится к трем довольно разным сторонам этой технологии: MongoDB, HBase и Redis. Очень вероятно, что то, что я отношу к неотъемлемым преимуществам SQL, могут отлично делать другие НРБД. Причина написания этого поста в том, что я встречаю множество людей утверждающих, что NoSQL намного проще для создания прототипов, чем SQL. И с этим я несколько не согласен.
Схемы – великолепны
Похоже, что многие люди страшно боятся понятия схемы. Схема == явная типизация == убийца продуктивности труда. Проблема с этим утверждением в том, что оно основано на идее, что от схемы можно полностью избавиться. К сожалению, эта идея является несбыточной мечтой. В какой-то момент вы должны иметь понимание того, с чем вы имеете дело: вы должны знать, какого типа текущее значение. Если мы не хотим описывать типы в программировании, у нас есть несколько вариантов. Например, мы можем проанализировать код, чтобы понять какого типа будет переменная в определённый момент времени, как это делается в языке программирования Rust. Или мы можем прибегнуть к тому, что делает Python или JavaScript: переключиться на динамическую типизацию и решить проблему на этапе выполнения.
Эта проблема значительно существеннее в базах данных, потому что мы говорим не об отдельных переменных, а о целых коллекциях. Вы рассматриваете вашу НРБД как сущность, в которую вы кидаете JSON-документы. Но даже не объявив схему вы держите её в уме если работаете с коллекциями объектов. Предполагая, что вы найдёте общее количество комментариев в вашем блоге, подсчётом количества комментариев каждого поста – вы используете схему. Вы ожидаете, что число комментариев каждого поста – целое число, сумму которых необходимо сложить, чтобы операция имела смысл.
Схема в любом случае живёт в вашей голове. Проблема в том, что она не применяется должным образом и есть вероятность допустить ошибки. Если вы храните строку там, где в другой коллекции вы сохранили целое число, никаких проблем не будет, пока вы размышляете в рамках одного документа. В противном случае ваши коллекции внезапно оказываются несогласованными.
Оказывается, что даже если вы явно не используете схему, ваши НРБД всё равно используют некоторые её остатки для индексации. Несмотря на то, что люди могут вам сказать, НРБД – это не магия. Они работают под такими же ограничениями, как и любые другие хранилища данных, и нуждаются в явной индексации, чтобы быть быстрыми.
Я определенно люблю схемы. Но я не знал насколько я их люблю, пока они внезапно не исчезли. Все стало грязным, и первое, что я добавил в наш код – это систему типизации, чтобы получить схему.
Знаете ли вы чего хотите?
Отсутствие схемы не должно быть причиной, чтобы не использовать MongoDB или любую другую НРБД. Легко добавить схему как надстройку, и такие вещи как MongoEngine для Python уже делают это за вас. Поэтому я не столько обеспокоен проблемой недостатка схем, сколько всеохватывающей идеей денормализованных данных.
Денормализованные данные – это клёво, без всяких сомнений. Их можно быстро и легко понять, и денормализация в нескольких нереляционных хранилищах намного проще, чем в SQL, потому что вы можете легко поместить данные куда необходимо. Это будет работать пока вы знаете, что делаете. К сожалению, иногда происходит непредвиденное и тогда вы понимаете, что у вас есть данные, к которым у вас нет доступа. Это то, что случилось со мной несколько раз на этой неделе.
По причинам, слишком сложным, чтобы объяснить здесь, я должен был извлечь информацию, которая была представлена не в том формате, в котором мне было необходимо. Все было так удивительно хорошо денормализованно, что попытки получить данные оказались кровавым месивом. С SQL-ориентированной БД это можно было бы сделать с помощью нескольких JOIN’ов и GROUP BY. А всё потому, что это писалось без догадки, что мне понадобятся данные в совершенно ином формате.
Убит “Слишком сложным”
За последний месяц я извлёк для себя, что большая ценность в том, чтобы быстро приспосабливаться к изменениям. Мы были счастливы представить нашу игру в iTunes на Рождество в нескольких странах. Внезапно мы получили намного больше игроков, чем можно было ожидать. Нам понадобились ответы на вопросы, которые мы и не предполагали, что будем задавать, и наша модель данных делает непростым получение ответов.
Мне нравится верить, что наша команда вполне способна, и мы выбираем технологии с большой осторожностью, но всегда есть вещи, которые вы прозеваете.
MongoDB и другие НРБД удивительны, если вы уже всё знаете. Нет никаких сюрпризов. Все, что вам нужно – это масштабировать успешный продукт. Если же ваш продукт новый, большая ценность в том, чтобы быть гибким и иметь возможность получить информацию из данных быстро, даже если изначально вы такого не предполагали.
SQL базы данных, делают это относительно простым занятием и не заставляют вас страдать за отсутствие надлежащего планирования. Если запросы становятся медленными, вы можете просто добавить индексы в тех местах, в которых это необходимо. В некоторых НРБД это не сработает. В Redis вы формируете структуры данных вручную, и если изначально они неверны у вас появляется проблема. В MongoDB наличие или отсутствие индексации меняет результаты выборки иногда, и может сделать добавление индексов нетривиальной задачей.
Ещё хуже то, что иногда вы просто не можете добавить индексацию. Если у вас есть вложенные объекты, сложно просто запросить некоторые из них, т.к. они содержатся в других объектах. Поскольку БД не предоставляет запросов для таких нужд, не сложно оказаться в ситуации, когда вы вынуждены извлечь все данные для их автономной обработки через MapReduce.
Это даже не проблема, это просто часть архитектуры базы данных. Тем не менее, мы столкнулись с этим как с проблемой. К сожалению, иногда мир ведёт себя не так как должен. Вы сталкиваетесь с непредвиденными ситуациями, и нет ничего более утомительного, чем сидеть на ваших данных и не быть в состоянии получить информацию, когда вы знаете, что она там.
Так что, по крайней мере, для себя я понял, что не смогу предсказать всё наперед, поэтому пока у меня будет возможность, я буду использовать более гибкие хранилища данных, и на данный момент это значит, что я буду использовать SQL базы данных.
И я всё ещё люблю тебя MongoDB.
Автор: Frolenarzt