Экспресс-курс · No. 06

Языки и фреймворки приходят и уходят. Данные, которые ты хранишь, и форма, в которой ты их хранишь, могут пережить их все — поэтому выбрать базу значит выбрать, как твоя система помнит и насколько тяжело ей передумать.

Только суть · Один образ на хранилище · Примеры важнее бенчмарков

§ 01

База данных — это долговременная память твоей системы. Код переписывают; данные и форма, которую ты для них выбрал, обычно переживают всё вокруг.

Данные переживают код

Дом за десятилетия перекрашивают, переставляют мебель, даже перекрывают крышу — но фундамент, залитый в первый день, остаётся, потому что заменить его значит поднять весь дом.

Языки меняются, фреймворки подменяют, интерфейс перерисовывают десять раз. Данные и их структура обычно остаются, потому что менять их на живой системе, полной реальных записей, медленно и рискованно. Поэтому база — первое, о чём надо подумать всерьёз, и последнее, что стоит делать впопыхах.

База отвечает на два вопроса

Выбор, где хранить вещи, задаёт два вопроса: какой они формы — книги на полках или странные инструменты на крючках? — и насколько надёжно их надо беречь — сейф или удобный ящик?

Любое хранилище определяется тем, как оно придаёт данным форму (жёсткие таблицы, гибкие документы, граф связей) и что оно гарантирует (строгую корректность или скорость и доступность с более слабыми обещаниями). Почти любой выбор базы — это разный ответ на эти два вопроса, и остальной курс — это меню.

Выбирай по тому, как читаешь и пишешь, а не по хайпу

Картотечный шкаф, каталог карточек и конвейер — всё это «хранилище», но выбираешь ты по тому, как будешь доставать вещи, а не по тому, что выглядит новее.

Лучшей базы не бывает. Хранилище, идеальное под быстрые поиски по ключу, плохо для глубоких запросов по связям; построенное под огромные записи плохо для строгих банковских транзакций. Правильный вопрос — твой паттерн доступа: что ты читаешь, что пишешь, как часто и как это должно вести себя, когда что-то идёт не так.

Код легко поменять. Данные — нет. Выбирай хранилище как решение, с которым проживёшь годы, — потому что так и будет.

§ 02

Для большинства систем дефолт — реляционная база, и этот дефолт она заслуживает. Начинай отсюда и уходи только с причиной.

Таблицы, строки и связи

Правильно сделанная таблица: каждый лист — один вид сущности (клиенты, заказы), каждая строка — одна запись, и заказы ссылаются назад на клиента, которому принадлежат.

Реляционные базы (Postgres, MySQL) хранят данные в таблицах с фиксированной схемой и связывают таблицы по ссылке — строка заказа держит id своего клиента. Схема — это обещание о форме: у каждого заказа есть нужные колонки, проверенные на входе. Структура заранее в обмен на здравомыслие потом.

ACID: корректность по принципу «всё или ничего»

Денежный перевод — это две записи: минус здесь, плюс там, — но одно намерение. Либо обе случились, либо ни одна; наполовину сделанный перевод — катастрофа.

Реляционные базы дают транзакции с гарантиями ACID: группа изменений либо целиком фиксируется, либо целиком откатывается, изолированно от других, и переживает падение, как только подтверждена. Поэтому банки, заказы и склад живут в SQL — когда корректность важнее голой скорости, тебе нужно именно это обещание.

SQL: проси что хочешь, а не как достать

Ты говоришь библиотекарю «все романы французских авторов, изданные после 1950-го, по году» — и он сам соображает, как их найти. Ты описываешь результат, а не поиск.

SQL — это декларативный язык запросов: ты заявляешь нужный ответ, а база планирует, как его достать, включая соединение таблиц. SELECT ... JOIN ... WHERE ... может ответить на вопросы, которых ты не предвидел при проектировании, — одна из тихих суперсил реляционной модели.

Почему это правильный дефолт

Хороший универсальный инструмент: не самый быстрый в каком-то одном деле, но тот, за которым тянешься, пока задача специально не потребует иного.

Структурированные данные, реальные связи, произвольные запросы, сильные гарантии — реляционная база делает всё это хорошо, а современный Postgres ещё и тянет JSON, полнотекстовый поиск и даже векторы. Начинай каждый проект здесь; тянись за чем-то другим, только когда конкретная боль — масштаб, форма или паттерн доступа — выталкивает тебя.

Начинай с Postgres. Вопрос не «зачем SQL» — а есть ли у тебя реальная причина его не брать.

§ 03

Иногда жёсткая таблица — неправильная форма. «NoSQL» — это на самом деле семейство хранилищ, и каждое гнёт правила в свою сторону ради своей задачи.

Документные: по JSON-блобу на сущность

Папка заполненных анкет, где у каждой могут быть слегка разные поля — нет центрального шаблона, заставляющего все совпадать.

Документные базы (MongoDB) хранят записи как гибкие JSON-подобные документы, вложенные и почти бессхемные, так что две записи в одной коллекции могут различаться. Хорошо, когда формы разнятся или быстро меняются, и целая сущность — товар, профиль — живёт как один документ, который ты достаёшь за одно чтение. Цена: меньше гарантий и сложнее запросы между документами, чем в SQL.

Ключ-значение: гигантская хеш-таблица

Гардероб — отдаёшь номерок, получаешь ровно своё пальто. Никаких поисков, никаких вопросов, мгновенно.

Хранилища ключ-значение (Redis, DynamoDB) — простейшая форма: ключ на входе, значение на выходе, ослепительно быстро. Идеально для кэша, сессий, счётчиков rate-limit и всего, что ты достаёшь по известному id. Размен: искать можно только по ключу — богатых запросов по самим значениям нет.

Широкие колонки: под огромные записи

Огромный склад с бесконечными одинаковыми проходами, устроенный так, чтобы тысяча погрузчиков расставляла товар одновременно, не сталкиваясь.

Хранилища широких колонок (Cassandra) размазывают данные по множеству машин ради огромной пропускной способности записи и масштаба, меняя богатые запросы и строгую согласованность на способность принять брандспойт данных. Используются для логов событий, телеметрии и лент на масштабе, где одна SQL-машина прогнулась бы. Мощно — и больше работы по эксплуатации.

Графовые: когда суть в связях

Доска детектива — фото, соединённые нитями. Ценность не в отдельном фото, а в паутине того, кто с кем связан.

Графовые базы (Neo4j) моделируют данные как узлы и рёбра между ними, делая запросы по связям — «друзья друзей, которым это нравится», «путь между этими двумя аккаунтами» — естественными и быстрыми там, где SQL понадобились бы болезненные многосторонние соединения. Дом социальных графов, рекомендаций и выявления мошенничества. Тянись за этим, когда связи важнее самих записей.

NoSQL — это не «новее SQL». Каждое хранилище сбрасывает какую-то гарантию ради чего-то конкретного — знай, чем именно ты жертвуешь.

§ 04

За универсальными хранилищами стоят базы, сделанные под одну задачу, где специализированный движок обходит универсальный на голову.

Временные ряды: данные со штампом времени

Лента кардиомонитора — бесконечная полоса показаний, каждое привязано к моменту, и ты почти всегда спрашиваешь «что было между этими двумя временами?»

Базы временных рядов (InfluxDB, TimescaleDB) заточены под данные, которые приходят по порядку времени и запрашиваются по времени — метрики, показания датчиков, цены. Они принимают огромные потоки и быстро отвечают «среднее за минуту за прошлую неделю», со встроенным истечением старых данных. Когда у всего, что ты хранишь, есть метка времени и время — главная ось, это твой выбор.

Поисковые движки: полный текст и релевантность

Строка поиска, которая прощает опечатки, ставит лучшие совпадения первыми и находит «running», когда ты набрал «run», — как библиотекарь, понимающий, что ты имел в виду.

Поисковые движки (Elasticsearch, OpenSearch) индексируют текст ради быстрого полнотекстового поиска с ранжированием, нечётким совпадением и фильтрами — того, что LIKE '%word%' в SQL делает медленно и плохо. Обычно работают рядом с основной базой, держатся в синхроне и питают строку поиска и разбор логов. Не источник правды — быстрая линза на него.

Векторные базы: поиск по смыслу

Вместо совпадения точных слов ты спрашиваешь «найди то, что похоже на это» — и получаешь соседей по сходству, а не по ключевому слову.

Векторные базы (pgvector, Pinecone) хранят embeddings — числовые отпечатки смысла — и находят ближайшие, так что ты ищешь по сходству, а не по точному тексту. Это движок под семантическим поиском и RAG, где AI-приложение достаёт самые релевантные куски, чтобы из них ответить. Новое обязательное хранилище эпохи AI.

Объектное хранилище: куда кладут большие файлы

Бокс на складе самообслуживания — не для карточек, а для мебели: громоздкие вещи, которые держишь по ярлыку и вывозишь целиком.

Объектное хранилище (S3 и его собратья) — не база данных, но именно туда кладут большие блобы — картинки, видео, бэкапы, документы — адресуемые ключом и отдаваемые дёшево на масштабе. Паттерн почти универсален: файл — в объектном хранилище, а строку, указывающую на него, — в базе. Записи в БД, нагрузка в бакете.

Не выгибай основную базу в поисковый движок или файловый сервер. Специализированную задачу клади в хранилище, построенное под неё.

§ 05

Самый глубокий выбор базы — не её форма, а то, что она обещает, когда что-то идёт не так. Небольшой алфавитный суп называет этот размен.

ACID: пессимистично, корректно, осторожно

Кассир в банке, который перепроверяет каждую запись и не двинется дальше, пока книги не сойдутся, — медленнее, зато никогда не ошибается.

ACID (Atomicity, Consistency, Isolation, Durability) — строгое обещание реляционных баз: каждая транзакция оставляет данные корректными и полными или не происходит вовсе. Ты платишь некоторой скоростью и более тяжёлым масштабированием по машинам. Для денег, заказов и всего, где неверное число недопустимо, это тот размен, что тебе нужен.

BASE: оптимистично, доступно, в итоге верно

Оживлённый магазин, где всем дают покупать, даже пока обновляют ценники, — числа догонят через миг, и это нормально.

Многие NoSQL-системы занимают противоположную позицию: BASE (Basically Available, Soft-state, Eventually consistent). Они остаются быстрыми и доступными и принимают, что копии данных могут ненадолго расходиться, прежде чем сойтись. Идеально, когда доступность важнее мгновенной точности — счётчик лайков, лента, счётчик просмотров, — и секунда устаревания ничего не стоит.

CAP: при обрыве сети выбери два из трёх

Команда, разрезанная упавшей телефонной линией: каждая половина может работать сама (но они разойдутся) или сложить инструменты до восстановления связи (но ты встаёшь). И то, и другое сразу — нельзя.

Теорема CAP говорит: когда сетевой раздел разрезает машины твоей базы, ты должен выбрать Consistency (отказывать в записи, оставаться корректным) или Availability (продолжать обслуживать, рискуя расхождением) — оба сразу во время раздела невозможны. Любая распределённая база делает этот выбор. Знать, что выбирает твоё хранилище, — значит знать, как оно ведёт себя в худший день.

ACID для денег, BASE для лайков. Нужная гарантия задаётся ценой того, чтобы ненадолго ошибиться.

§ 06

Горстка приёмов превращает базу из одной хрупкой коробки в нечто быстрое и живучее. Со всеми ты столкнёшься.

Индексы: предметный указатель для данных

Чтобы найти слово в книге на 900 страниц, ты не читаешь каждую страницу — ты открываешь указатель в конце и прыгаешь прямо к нему.

Индекс — это побочная структура, превращающая полный перебор таблицы в прямой поиск, самый большой рычаг скорости чтения. Подвох: каждый индекс стоит места и замедляет записи (каждая вставка должна обновить и его). Поэтому индексируешь колонки, по которым реально фильтруешь и сортируешь, — не все подряд на всякий случай.

Репликация: держи копии, переживай отказ

Документ, хранимый в трёх сейфах в трёх зданиях — если одно сгорит, другие всё равно держат его, и трое могут читать одновременно.

Репликация держит копии данных на нескольких машинах: если лидер умирает, его место занимает реплика, а чтения можно размазать по копиям. Это покупает надёжность и масштабирование чтений. Подвох — лаг репликации: реплика может отставать на миг, так что только что записанное значение может ещё не показаться на ней.

Шардинг: дели, когда одной машины мало

Один переполненный картотечный шкаф становится A–M в одном шкафу и N–Z в другом. Больше места — но теперь надо знать, в каком шкафу живёт имя.

Когда данные или нагрузка на запись перерастают одну машину, шардинг делит данные по многим — пользователи A–M здесь, N–Z там. Это открывает почти безграничный масштаб, но ключ шардирования — тяжёлый, почти необратимый выбор: ошибёшься — получишь горячие точки или запросы, которым приходится бить по всем шардам. Репликация копирует одни и те же данные; шардинг делит разные.

Нормализуй, потом денормализуй осознанно

Один общий список адресов, на который все ссылаются (без противоречий), против пришитой копии адреса к каждому заказу (читать быстрее, но теперь есть копии, которые надо держать честными).

Нормализация держит каждый факт ровно в одном месте — чисто, без противоречий, реляционный дефолт. Денормализация намеренно дублирует данные, чтобы чтения были быстрее и требовали меньше соединений. Оба подхода годятся; правило — делать это осознанно и всегда знать, какая копия источник правды, а какая просто быстрый дубль. (Тот же урок, что с кэшем.)

Сначала индекс, потом сервер; сначала реплика, потом шард. Самое дешёвое масштабирование — то, которое не приходится эксплуатировать.

§ 07

Ты не выбираешь одну базу и не запихиваешь в неё всё. Реальные системы используют несколько, каждую под задачу, в которой она лучше всего.

Polyglot persistence: несколько хранилищ осознанно

На кухне есть холодильник, морозилка и кладовка — а не одна коробка, заставленная делать всё три. Каждая держит то, что ей подходит.

Зрелые системы обычно полиглотны: Postgres как источник правды, Redis для кэша и сессий, поисковый индекс для строки поиска, может быть, векторное хранилище для AI-фич и объектное хранилище для файлов. Каждое делает то, в чём хорошо. Дисциплина в том, чтобы ясно держать, какое из них хранит правду, а остальные — быстрые копии, держащиеся в синхроне.

Начинай с Postgres; вырастай из него осознанно

Швейцарский нож тянет поразительно много, прежде чем тебе вообще понадобится полный набор инструментов.

Современный Postgres поразительно способен — реляционное ядро, JSON-документы, полнотекстовый поиск, векторы, даже рабочая очередь задач. Большинство продуктов должны начинать просто с Postgres и добавлять специализированное хранилище, только когда реальная, измеренная боль этого требует. Каждая лишняя база — это ещё одно, что надо эксплуатировать, бэкапить и держать согласованным. Самое дешёвое хранилище — то, которое ты не добавил.

Прежде чем выбрать базу
  • Какой формы данные — таблицы, документы, ключ-значение, граф? - Как я буду их запрашивать — по id, по связям, по тексту, по сходству, по времени? - Какие гарантии мне нужны — строгий ACID или сойдёт eventually consistent? - Каков баланс чтений/записей и примерный масштаб? - Не смог бы Postgres уже это сделать, прежде чем я добавлю ещё хранилище?
  • Какое хранилище держит источник правды, а какие — просто копии?
Признаки, что ты выбрал не то
  • Ты гоняешь LIKE '%...%' для поиска вместо поискового движка. - Хранилище ключ-значение там, где постоянно нужно запрашивать по значениям. - Пять баз для продукта, который поддерживают два человека. - Ты взял MongoDB, чтобы избежать схем, а потом всё равно руками собрал валидацию. - Нет ясного источника правды — два хранилища оба претендуют на авторитет.
Признаки, что ты выбрал хорошо
  • Запрос, который ты гоняешь чаще всего, — тот, в котором хранилище быстрее всего. - Гарантия соответствует ставкам — строгая для денег, расслабленная для лайков. - Ты можешь назвать источник правды для каждого важного факта. - Ты добавил каждое хранилище, чтобы решить реальную, прочувствованную боль, а не гипотетическую. - Ты мог бы объяснить модель данных новому инженеру за несколько минут.

Лучшее решение по базе обычно — «Postgres, пока что» — плюс мудрость понять ровно тот момент, когда «пока что» закончилось.

Конец экспресс-курса · 7 глав · хранилища важнее бенчмарков

Дальше — глубина: «Designing Data-Intensive Applications» Мартина Клеппманна — та самая книга, которую стоит прочесть, плюс документация Postgres и руководство твоего хранилища. Но прежде глубокой воды — представь, как твои данные будут читать, писать и кому доверять. База — это место, где система помнит; выбери, как она помнит, прежде чем выбирать, на чём она построена.