Когда реляционное хранилище плохо подходит
Что это такое
Неподходящим инструментом реляционный движок оказывается в четырёх ситуациях. Форма данных в них различается от записи к записи и не описывается стабильным набором столбцов; доступ идёт всегда по одному ключу и никогда по условию; объём или темп записи превышает то, что выдерживает один сервер; а естественное представление данных — граф связей, обходимый на много уровней вглубь. За каждым из этих случаев стоит настоящее несоответствие, а не чьё-то предпочтение.
Почему это важно
Распознать несоответствие — значит предотвратить обе стандартные ошибки. Одну из них делают, когда навязывают реляционную схему данным, у которых её нет, другую — когда берут нереляционное хранилище для данных, у которых она есть. За схемой с сорока nullable-столбцами обычно стоит модель документа, втиснутая в строки; за документным хранилищем, которое обходят соединениями в коде приложения, — обычно реляционная модель, втиснутая в документы. Назовите несоответствие первым, и выбор хранилища будет следовать из данных, а не из моды.
Ключевые идеи
Стабильный набор столбцов — допущение, которое стоит проверить
Реляционная модель предполагает, что у всех строк таблицы один и тот же набор атрибутов. Когда записи действительно различаются, схема либо обрастает nullable-столбцами, либо переносит изменяющуюся часть в нетипизированный блоб. Каталог, в котором смешаны книги, загрузки и курсы, служит тому примером: поля у этих записей разные. Если большинство столбцов пусты у большинства строк, допущение не выполняется.
строка 1: title, author, pages (книга)
строка 2: title, duration, resolution (загрузка)
одна таблица -> почти всё null, или нетипизированный блоб
Выборка всегда по одному ключу — это другая задача
Реляционный движок построен, чтобы отвечать на вопросы, которых ещё не видел, а для этого ему нужны индексы и планировщик. Нагрузка, которая всегда спрашивает только «дай значение по этому ключу», платит за механизмы, которых не использует, тогда как хранилище ключ-значение отвечает на такой запрос с меньшими накладными расходами. Именно так устроены данные сессий, флаги функций и кэши, где выборка по ключу — единственный вид доступа.
Объём записи может перерасти одну машину
Когда записи приходится распределять по многим машинам, реляционная гарантия того, что транзакция охватывает их все, становится дорогой или вовсе недоступной. Хранилища, которые эту гарантию ослабляют, распределяются гораздо легче — но приложению приходится самому рассуждать о согласованности в конечном счёте. На масштабе это настоящее ограничение, а на размерах, до которых доходит большинство систем, — ненужное.
Глубокий обход — это задача о графе
Поиск друзей друзей друзей есть соединение, повторённое неизвестное число раз; язык запросов выражает его неуклюже, а графовое хранилище — напрямую. Там, где связи и есть данные, а не способ их соединить, графовая модель подходит лучше, и запросы получаются проще.
Гибкая схема переносит решение, а не отменяет его
Документное хранилище принимает любую форму, и во время разработки это удобно; однако каждый читатель после этого должен справляться с любой формой, которая когда-либо была записана. Схема никуда не исчезает — её обеспечивает код приложения, который эти данные читает, а не хранилище. Если считать гибкость бесплатной, коллекция документов быстро накопит десяток вариантов одной записи.
Несоответствие в шаблонах доступа, а не в размере
Нереляционное хранилище обычно обосновывают масштабом, а на деле нагрузка невелика, зато схема неудобна. Искать несоответствие нужно в том, как данные устроены и читаются, а не в том, сколько их. Реляционная база хранит куда больше, чем большинство систем когда-либо сохраняет.
Практика
Классифицируйте три набора данных
Возьмите хранилище сессий, каталог товаров с разными атрибутами и социальный граф и скажите для каждого, что его описывает: стабильная схема, доступ по одному ключу или глубокий обход.
Готово, когда: каждый набор сопоставлен свойству, которое решает выбор хранилища, и ни один не обоснован только размером.
Найдите таблицу с nullable-столбцами
Поищите таблицу, где большинство столбцов равны null у большинства строк, и опишите, какую форму документа она имитирует.
Готово, когда: вы можете назвать изменяющиеся атрибуты и сказать, действительно ли они переменные или лишь разреженные.
Частые ошибки
- Выбор нереляционного хранилища ради недостигнутого масштаба — реляционные гарантии отдаются ни за что; исправить: основывайте решение на шаблонах доступа, а не на предполагаемом объёме.
- Втискивание переменных данных в nullable-столбцы — ограничения теряют смысл, а запросы усложняются; исправить: рассмотрите форму документа или выделите изменяющуюся часть в отдельную таблицу.
- Предположение, что у хранилища без схемы схемы нет — читатели должны обрабатывать каждую историческую форму; исправить: определите и валидируйте форму на границе.
- Использование документного хранилища для моделирования связей — соединения переезжают в код приложения и теряют гарантии движка; исправить: оставьте связи там, где обход и есть цель.
- Отношение к семействам как к взаимозаменяемым — ключ-значение, документные, ширококолоночные и графовые решают разные задачи; исправить: назовите задачу прежде, чем называть хранилище.
Что читать дальше
- NoSQL (05-backend-data/13-nosql) — семейства, к которым ведут эти несоответствия, поэтому читайте её первой.
- Семейства нереляционных хранилищ (05-backend-data/13-nosql/02-the-families-of-non-relational-stores) — что каждое семейство даёт взамен.
- SQL и реляционные базы данных (05-backend-data/07-sql-relational-databases) — допущения, которые здесь и проверяются.