---
title: Статья 04 — Модели данных и выбор хранилища
source: подготовлено 2026-09-17, TASK-45.44; каркас — brief.md §04; развёртка knowledge-base.md §3–3.1 (мосты в §5–6); источники — DDIA 2-е изд. гл. 3–4 (TASK-45.39), Alex Xu гл. 5–6 (TASK-45.38), эталоны classic-designs.md §1–3
---

# Статья 04: модели данных и выбор хранилища

Четвёртая статья серии — про главный контент этапа 4 («детали + БД», 18 минут секции): какие классы хранилищ существуют, как выбирать между ними и как они устроены внутри. Критерий «умею, если» из брифа: **для любого кейса называю класс хранилища + 2 аргумента за и 1 против**. Обратите внимание на форму критерия: не «назвать продукт» и не «назвать класс» — назвать класс и обосновать трейдоффом. «Возьмём Cassandra» без гарантий и критериев — ошибка №5 методички, и это самый частый способ провалить именно этот этап.

Место раздела в каркасе: статья 03 ([`03-scaling.md`](03-scaling.md)) закончилась словами «стейт — в правильных местах» — эта статья отвечает, **какие** это места; статья 05 ([`05-replication-sharding.md`](05-replication-sharding.md)) — как выбранные хранилища переживают рост и отказы. Связка с соседями: KV-класс и кэш — родня, но кэш как слой — отдельный раздел 06; событийная синхронизация проекций — материал раздела 07; гарантии согласованности, которыми мы платим за выбор — раздел 09; поведение хранилищ при отказах — раздел 08. Глубина — [`../knowledge-base.md`](../knowledge-base.md) §3–3.1; первоисточник обеих половин статьи — DDIA гл. 3 (модели) и гл. 4 (движки).

## 1. Что на самом деле выбираем: модель, гарантии, масштаб

Вопрос «SQL или NoSQL?» поставлен неправильно — и это первая фраза, которую стоит произнести на секции. Выбираем не лагерь, а **пакет из трёх решений**:

- **Модель данных** — в какой форме живут данные: таблицы со связями, документы-агрегаты, пары ключ-значение, граф, столбцы. Модель определяет, какие запросы **естественны** (один оператор), а какие — мучительны (ручные циклы в приложении). DDIA: приложение — это слои моделей (объекты кода → модель данных → байты на диске), и каждый слой задаёт словарь следующего.
- **Гарантии** — транзакции, изоляция, целостность: строгие у реляционных СУБД (ACID, schema-on-write, ограничения и внешние ключи), ослабленные у большинства NoSQL (eventual consistency, schema-on-read). Это мост в раздел 09.
- **Масштаб и характер нагрузки** — read или write, точечные или range-запросы, какой объём и RPS: здесь выбор решают не «религии», а устройство движков (§5) и данные оценок (статья 02).

Классическая пара трейдоффов внутри «модели»: **schema-on-write против schema-on-read**. Реляционная схема — это защита: испорченную запись в неё не вставить, ошибка ловится в момент записи. Гибкая схема документных БД — это скорость эволюции, но ошибки структуры переносятся в рантайм и становятся ответственностью приложения. Формула ответа: «гибкую схему беру там, где данные реально вариативны (каталог, контент, события разных типов), и не беру там, где домен чёткий и за данные платят деньгами».

И обязательная оговорка про конвергенцию: противостояние давно размылось — в PostgreSQL живёт полноценный JSONB, Mongo научился multi-document-транзакциям, managed-слои приносят шардирование в SQL. Поэтому «у нас реляционная СУБД» больше не означает «не масштабируется», а «у нас NoSQL» не означает «нет транзакций». Спорят не тезисы, а конкретные трейдоффы — их и называем.

## 2. Классы хранилищ: карта с критерием «2 за — 1 против»

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

| Класс | Представители | За ×2 | Против ×1 | Кейсы |
|-------|---------------|-------|-----------|-------|
| **Реляционная** | PostgreSQL, MySQL | ACID-транзакции и ограничения целостности; сложные запросы и JOIN, зрелость экосистемы | масштаб записи упирается в одну ноду, шардинг — руками | деньги, заказы, связи сущностей, источник правды; до единиц ТБ |
| **Документная** | MongoDB, Couchbase | агрегат «документ = объект домена» читается одним куском (локальность); гибкая схема | JOIN и связи между агрегатами слабые, транзакции между документами — боль | профили, каталоги, контент с вариативной структурой |
| **Key-value** | Redis, DynamoDB | O(1) по ключу, гигантский RPS на ноду; горизонтальный масштаб и TTL | нет JOIN и сложных запросов; Redis — память (дорого, ограничен объём) | сессии, счётчики, фичи-флаги, кэш, hot path по известному ключу |
| **Wide-column** | Cassandra, HBase, Bigtable | write-throughput на последовательных записях (LSM); равномерное партиционирование по ключу, линейный масштаб | модель заточена под запросы по ключу партиции; ad-hoc-запросы и точечные обновления — плохо | приём событий, истории сообщений, write-heavy временные ряды |
| **Колоночная (аналитика)** | ClickHouse, BigQuery | агрегации по миллиардам строк со сканом столбцов; сжатие в разы | не для OLTP: нет точечных UPDATE, транзакции слабые | логи, аналитика, отчёты, event-store «для чтения» |
| **Поисковая** | Elasticsearch, OpenSearch | инвертированный индекс: полнотекст, морфология, fuzzy, фасеты | не источник правды — eventual-проекция; дорогая запись | поиск по тексту, автодополнение, лог-поиск |
| **Time-series** | Prometheus, VictoriaMetrics, InfluxDB | retention и даунсемплинг из коробки; быстрые оконные агрегаты | специализированная модель — только время как ось | метрики, мониторинг, телеметрия |
| **Графовая** | Neo4j | index-free adjacency: траверсы связей N-го порядка за постоянное время на шаг | нужна редко; массовые обходы большого графа дороги | соцграф-запросы, рекомендации, fraud-цепочки |
| **Объектная** | S3, GCS, MinIO | почти бесконечный масштаб и дешевизна; durability 11 девяток | высокая латентность, нет запросов по содержимому | медиа, бэкапы, стейджинг для batch |
| **Event log** | Kafka | append-only лог: реплей истории, retention, десятки МБ/с на партицию | не queryable, порядок гарантирован только внутри партиции | интеграция сервисов, event sourcing, конвейеры |

Три уточнения, которые отличают уверенный ответ:

- **Wide-column и «колоночная» — разные классы**, несмотря на похожие слова. Wide-column (Cassandra) — про **запись** потока строк с гибким набором колонок, семейство KV; колоночная (ClickHouse) — про **чтение агрегатов**, хранение по столбцам. «Колоночный» в первом случае — модель строки, во втором — физическая раскладка байтов.
- **KV и wide-column — ближайшие родственники**: оба про «ключ → данные», оба на LSM-движках (§5). Отличие в модели: у KV значение непрозрачно, у wide-column внутри ключа — отсортированный набор колонок, что даёт range-запросы внутри партиции (история диалога — канонический кейс).
- **Графовая БД — самая редкая покупка**. Запрос «друзья друзей» в реляционной СУБД — один JOIN и работает нормально; графовая оправдана, когда связи — сами данные и глубина траверсы не ограничена (рекомендации, цепочки мошенничества). На секции честнее сказать «соцграф держу в шардированной реляционной по user_id, а глубинные обходы — отдельно» — это и есть трейдофф-мышление, а не подбор продукта под слово из задания.

## 3. Таблица «кейс → хранилище»

Сводная таблица для этапа 4: типовой кейс из секций уровня «инстаграм/твиттер» → класс → чем обосновываем. Формат каждой строки — готовый ответ по критерию: класс + за + против.

| Кейс в дизайне | Класс / представитель | Два «за» | Один «против» (и что платим) |
|----------------|----------------------|----------|------------------------------|
| Заказы, платежи, кошельки | Реляционная, PostgreSQL | ACID + ограничения целостности; JOIN и сложные отчёты | write-масштаб одной ноды — шарды руками (мост в 05) |
| Сессии, фичи-флаги, rate-limit счётчики | KV, Redis | O(1) и TTL из коробки; сотни тысяч RPS на ноду | данные в памяти: дорогой объём, обязательны TTL и eviction |
| Кэш лент, hot-путь чтения | KV, Redis-кластер | латентность в микросекундах; consistent hashing масштабирует кластер | кэш может врать — нужна инвалидация (раздел 06) |
| Профиль пользователя, каталог товаров | Документная, MongoDB | агрегат одним чтением; гибкая схема под вариативные поля | связи между агрегатами и JOIN — в приложении |
| Посты, статьи (источник правды) | Реляционная, шардированная по росту | целостность и предсказуемые запросы; 70 ТБ/год — шардами живут спокойно | горячий путь чтения мимо SQL — нужен кэш-слой (06) |
| Истории сообщений чата | Wide-column, Cassandra (или реляционная по conversation_id) | write-heavy на LSM; range по времени внутри партиции диалога | вторичные запросы мимо ключа партиции — scatter-gather |
| Приём событий, логи, метрики приёма | Wide-column / колоночная, Cassandra / ClickHouse | последовательная запись на LSM; сжатие столбцов | нет точечных UPDATE, спайки компактации (§5) |
| Аналитика и отчёты по миллиардам строк | Колоночная, ClickHouse | скан и агрегат столбцов с сжатием; SQL-совместимость | не для точечных обновлений — питаем из конвейера |
| Полнотекстовый поиск, автодополнение | Поисковая, Elasticsearch | инвертированный индекс: морфология, fuzzy, фасеты | проекция с лагом и дорогой записью — не источник правды |
| Метрики мониторинга продукта | Time-series, VictoriaMetrics | retention/даунсемплинг автоматом; оконные агрегаты | специализированная модель — не кладём туда домен |
| Фото, видео | Объектная, S3 + CDN | дешевизна и durability; разгрузка всего остального | латентность — лечим CDN; метаданные — отдельно в RDBMS |
| Интеграция сервисов, fan-out публикации | Event log, Kafka | реплей и retention; порядок в партиции | не queryable — читающие проекции строим отдельно |

Правило чтения таблицы: один и тот же сервис почти всегда занимает **несколько строк** — это нормально и правильно. Лента из эталона — пять хранилищ сразу (§7).

## 4. Источник правды один: полихранилищная архитектура

Как только хранилищ становится больше одного, появляется главный риск этапа 4 — и ошибка №10 методички («не рассмотреть частичные отказы хранилищ»). Каноническая архитектура, которой отвечаем:

**Источник правды один — реляционная СУБД. Всё остальное — производные проекции с известным лагом.**

- Проекция устарела или потерялась → она **перестраивается** из источника (пересев кэша, реиндекс поиска, пересчёт read-модели). Деградация латентности, не потеря данных — это витрина раздела 08.
- Синхронизация проекций — не «как-нибудь реплицируется», а **событийная**: outbox-паттерн + CDC (транзакция в источнике пишет событие в тот же коммит, конвейер раскладывает по проекциям; идемпотентность потребителя обязательна — мост в раздел 07, гарантии — в 09).
- Лаг каждой проекции называется **числом**: поиск отстаёт на секунды, кэш — на миллисекунды, аналитика — на минуты. «Известный лаг» — это SLO, а не приписка.

Формулировка на секцию целиком: «источник правды — PostgreSQL: деньги и связи; hot-путь — Redis-зеркало с инвалидацией по событиям; поиск — Elasticsearch, реиндексируется из источника; аналитика — ClickHouse, питается конвейером. Расхождение проекций ловим мониторингом лага, восстанавливаем пересевом из источника». Одна фраза — и видно, что этап 4 у вас в руках.

## 5. B-tree vs LSM: «а как внутри вашей БД?»

Вопрос-зонд этапа 4, отличающий «назвал продукт» от «понимаю хранилище». Оба семейства — OLTP-движки, ответ держится на одной антитезе: **обновлять на месте против писать только добавлением**.

### 5.1 Прародитель: append-only лог

Простейшая БД — файл, в который записи дописываются в конец (пример DDIA: две bash-функции `db_set`/`db_get`). Запись O(1) и молниеносная (последовательная), но чтение — линейный скан. Вся история движков — ответ на вопрос «как искать по логу быстро»: hash-индекс в памяти (нет range), а дальше — два великих ответа: LSM и B-tree.

### 5.2 LSM-tree: запись как последовательные сегменты

**LSM** (RocksDB, Cassandra, HBase, LevelDB): запись попадает в **memtable** (отсортированная структура в памяти) → при заполнении сбрасывается на диск как **SSTable** — иммутабельный отсортированный файл со sparse-индексом и компрессией блоков → фоновая **компактация** сливает сегменты как mergesort. Удаление — **tombstone** (маркер, зачистка при компактации); **Bloom filter** отсекает чтения отсутствующих ключей. Стратегии компактации: size-tiered (сливаем равные свежие) vs leveled (уровни по размеру) — компромисс write-амплификации и пространства.

Что получаем: запись — **только последовательная**, отсюда высокий write-throughput и дешёвая компрессия. Что платим: чтение старого ключа может требовать обхода нескольких SSTable; range-запросы слабее (Bloom диапазоны не ускоряет); компактация конкурирует за IO с запросами → **латентность-спайки** и backpressure при недогоне.

### 5.3 B-tree: страницы и обновление на месте

**B-tree** (PostgreSQL, MySQL, почти вся классика): данные в страницах фиксированного размера (4–16 КиБ), обновление **на месте**, поиск за O(log n) — на практике глубина 3–4 уровня, чего хватает на сотни терабайт при ветвлении ~500. Заполнение страницы → **page split**; надёжность записи — **WAL**: сначала журнал с fsync, потом страница. Вариант copy-on-write (LMDB) даёт снапшоты без блокировок.

Что получаем: **предсказуемое точечное чтение** (всегда 3–4 уровня) и сильные range-запросы. Что платим: **write-амплификация** — одна логическая запись тянет WAL + перезапись страницы; случайные записи дороже последовательных.

### 5.4 Сравнение и выбор

| | **LSM** | **B-tree** |
|---|---------|-----------|
| Запись | быстрее: только последовательные сегменты, ниже write-амплификация | дороже: WAL + страница целиком на месте |
| Чтение | старый ключ — несколько SSTable; спайки от компактации | предсказуемо: 3–4 уровня страницы |
| Range | слабее (Bloom не помогает) | сильно (лист — отсортированный диапазон) |
| Компрессия | отличная (иммутабельные сегменты) | скромнее |
| Фон | компактация ест IO → джиттер латентности | ровнее, но page split + WAL |
| Где живёт | Cassandra, HBase, RocksDB, LevelDB, ClickHouse-семейство | PostgreSQL, MySQL, большинство RDBMS |

Нюанс, который любят слушать: на SSD последовательная запись всё равно быстрее случайной (erase block ~512 КиБ, GC контроллера), а write-амплификация изнашивает flash — поэтому LSM на flash-нодах особенно уместен.

Формула выбора: **write-heavy поток (приём событий, истории, метрики) → LSM-семейство; читающий профиль с range-запросами и транзакциями (домен, деньги) → B-tree-классика**. И связка с уже выбранными классами: это не два независимых решения — «Cassandra» из §2 автоматически означает LSM с его спайками, «PostgreSQL» — B-tree с его записью. На секции фраза «выбор класса у меня совпал с выбором движка: write-heavy кейс → LSM-семейство» закрывает зонд одним махом.

## 6. Индексы: платим записью за чтение

Индекс — любая дополнительная структура, которая существует **только** чтобы ускорить чтение, оплаченная замедлением записи и местом. Отсюда оба правила разом: индексы строим под access pattern (иначе зачем платим) и не строим «на всякий случай» (каждый лишний — налог на каждый INSERT/UPDATE).

Минимальный словарь, который нужен на секции:

- **Кластерный (первичный)** — сам порядок хранения данных: по ключу строки лежат физически (InnoDB — кластерный по PK). Определяет, что range-запрос по этому ключу читает последовательно.
- **Вторичный** — отдельная структура: ключ индекса → ссылка на строку. Hash — только equality-lookup; B-tree — и точечные, и диапазоны, и сортировку. По умолчанию в RDBMS — B-tree.
- **Составной** — по нескольким колонкам с правилом крайнего левого префикса: индекс `(user_id, created_at)` обслуживает «все посты пользователя по времени», но не «всё за сегодня по всем пользователям». Это правило прямо отвечает, почему индексы проектируют от запросов.
- **Покрывающий** — содержит все колонки запроса: чтение не идёт к строке вообще (index-only scan). Честная цена: индекс толще, запись дороже.

В распределённых системах (мост в статью 05, там развёрнуто) вторичные индексы делятся на **local** — каждый шард ищет сам, запрос по всем шардам (scatter-gather, дорого) — и **global** — индекс сам пошардирован по ключу индекса, поиск в один прыжок, но отстаёт от записи и страдает от hot spot'ов. Формула та же: «частые вторичные запросы → global ценой лага; редкие → local + scatter-gather».

И связка с лестницей масштабирования статьи 03: **индексы — первая ступень**, дешевейший способ ускорить чтение до всяких реплик, кэшей и шардов. «Сначала посмотрел планы и индексы» — зрелая фраза; «сразу поставим кэш» — нет.

## 7. Прикладное: лента и чат — критерий брифа

Применяем всё выше к двум сервисам-эталонам ([`../classic-designs.md`](../classic-designs.md) §2–3). Это готовый скелет этапа 4: каждое хранилище схемы — классом, представителем и обоснованием.

**Лента новостей** (инстаграм-класс) — пять хранилищ, каждое по своей строке таблицы §3:

- **Посты** — реляционная, шардированная при росте (70 ТБ/год — оценка из статьи 02): источник правды, целостность, запрос «пост по ID» — по ключу шарда. Против — горячий путь чтения мимо SQL: поэтому дальше кэш.
- **Ленты** — KV, Redis-кластер по user_id через consistent hashing: лента = ключ `user_feed:<id>`, микросекунды на горячем пути. Против — кэш может врать: инвалидация по событиям (раздел 06), пересев из источника.
- **Соцграф** — отдельная реляционная БД по user_id: горячий запрос постинга «подписчики автора» — одним шардом; глубинные рекомендации не на горячем пути (там, если дойдут, — графовое хранилище или офлайн-обходы).
- **Медиа** — S3 + CDN, метаданные — в той же реляционной БД постов.
- **Поиск и статистика** — Elasticsearch как проекция + ClickHouse для аналитики, питание через outbox/CDC (§4).

Формула этапа 4: «пять хранилищ — потому что пять access pattern'ов; источник правды один, остальные — проекции с лагом».

**Мессенджер** — спорный кейс, на нём показывают зрелость:

- **Сообщения** — write-heavy история с range-чтением «диалог по времени» → либо **wide-column** (Cassandra: партиция = conversation_id, история внутри партиции, LSM тянет поток записей), либо **реляционная с шардами по conversation_id** (транзакции и предсказуемость ценой ручного шардинга). Называть **оба варианта и трейдофф** — сильнее, чем выбрать один: LSM даёт запись, но спайки и слабые вторичные запросы; B-tree даёт транзакции, но write-масштаб строим шардами.
- **Онлайн-доставка** — не хранилище вовсе: stateless-шлюзы + реестр `user_id → gateway_id` в Redis с TTL (отдельно от истории); непрочитанные/счётчики — Redis (TTL, O(1)).

## 8. Ошибки этого раздела

Подмножество топ-10 ошибок ([`../methodology.md`](../methodology.md) §4), относящееся к выбору хранилища:

| Ошибка | Как выглядит | Противоядие |
|--------|--------------|-------------|
| «Возьмём Cassandra» (ошибка №5) | Продукт назван, гарантии и критерии — нет | Формат брифа: класс + 2 за + 1 против (§1–2) |
| «NoSQL, потому что масштаб» | Без чисел; read-heavy кейс на репликах SQL живёт спокойно | Сначала оценки (статья 02), потом класс; «влезает в одну ноду до единиц ТБ» |
| Одна БД на всё | Поиск LIKE'ом по таблице, аналитика JOIN'ом по миллиардам строк | Полихранилище: класс под каждый access pattern (§3) |
| Проекции без плана синхронизации (ошибка №10) | «Поиск как-нибудь реплицируется» | Источник правды + outbox/CDC + мониторинг лага (§4) |
| «Схема не нужна — гибкость» | Schema-on-read переносит порчу данных в рантайм | Schema-on-write — защита; гибкость только там, где реально вариативно (§1) |
| Redis как основная БД | Память под терабайты, persistence «настроим потом» | KV — hot path и временный стейт; правду держит RDBMS (§2) |
| LSM «быстрее на записи» везде | Не названы спайки компактации и дорогие чтения старых ключей | Таблица §5.4: write-heavy → LSM, читающий профиль → B-tree |
| Индекс на каждый столбец | Запись платит за десяток структур | Индексы под access pattern; составные с левым префиксом (§6) |
| Графовая БД «потому что соцсеть» | Neo4j под «друзья друзей», который живёт в одном JOIN | Глубина траверсы как критерий; соцграф на шардах по user_id (§2, §7) |

## 9. Что назвать на секции (чек-лист раздела)

Обязательные фразы и действия, по которым видно, что раздел освоен. Полный чек-лист этапов — [`../methodology.md`](../methodology.md) §7; канон — [`../knowledge-base.md`](../knowledge-base.md) §3.

**На этапе 2 (сущности и API):**
- Каждое хранилище на схеме называть **классом и представителем**, не просто «БД»: «посты — реляционная, PostgreSQL», «ленты — KV, Redis-кластер».
- Уже здесь проговорить роли: «это источник правды, это проекция» — архитектура полихранилища начинается с первого блока, а не с этапа 4.

**На этапе 4 (детали + БД) — ядро раздела:**
- Про каждое хранилище — **класс + 2 аргумента за + 1 против**. Это формальный критерий брифа; минимум один полный разбор сделать вслух целиком.
- «Выбираю не SQL vs NoSQL, а модель данных + гарантии + масштаб» — снять ложную дихотомию до того, как интервьюер её задаст.
- **Источник правды один (RDBMS), остальные — проекции с известным лагом** + как синхронизируются (outbox/CDC) + что при расхождении (пересев из источника, деградация, не потеря).
- На зонд «а как внутри вашей БД»: **B-tree против LSM** одной минутой — memtable/SSTable/компактация против страниц/WAL; вывод «write-heavy кейс → LSM-семейство, читающий профиль → B-tree» + назвать цену каждого (спайки против write-амплификации).
- Индексы — от access pattern: «составной (user_id, created_at) под ленту пользователя; покрывающий под горячий путь; каждый индекс — налог на запись».

**На этапе 5 (ресурсы):**
- Объём хранения → «влезает/не влезает в ноду»: единицы ТБ — реплики без шардов; десятки ТБ/год — шардирование (мост в статью 05), с числами-обоснованием из оценок.

**На этапе 6 (эксплуатация):**
- Отказ проекции (кэш, поиск) → деградация латентности, источник жив; отказ источника → failover (мост в 08) — различать эти два класса отказов явно.
- «Лаг проекций — метрика с алертом» — синхронизация без мониторинга считается несделанной.

**Сквозные формулы раздела:**
- «Класс + 2 за + 1 против» — формат любого ответа про хранилище.
- «Источник правды один, остальное — проекции с известным лагом».
- «Выбираю модель + гарантии + масштаб, а не лагерь».
- «Индекс — это платим записью за чтение».

## 10. Самопроверка «умею, если»

Критерий раздела из брифа: **для любого кейса называю класс хранилища + 2 аргумента за и 1 против**. Проверяется прогоном с закрытыми материалами: взять 5–7 кейсов из таблицы §3 вразброс (или из эталонов: URL shortener, медиа-хостинг) — на каждый 30–60 секунд: класс, представитель, два «за», один «против» с ценой. Затем зонды: «а как внутри вашей БД?» — LSM и B-tree по минуте с выводом о выборе; «почему не всё в одной БД?» — источник правды + проекции + синхронизация за три фразы; индексы — объяснить составной индекс через крайний левый префикс на примере ленты. Для ленты — полный полихранилищный список §7 от руки, пять хранилищ с ролями. Протокол тренировок и рубрика 0–3 — [`../methodology.md`](../methodology.md) §6; сверка с эталонами — [`../classic-designs.md`](../classic-designs.md) §1–3. Если на любой кейс ответ идёт по шаблону «класс → за → против» без пауз, а «как внутри» не вызывает ступора — раздел готов.

## Связанные документы

- [`00-overview.md`](00-overview.md) — обзорная статья по всем 12 разделам брифа (TASK-45.40)
- [`03-scaling.md`](03-scaling.md) — соседняя статья: лестница масштабирования, на которой индексы — первая ступень, а выбор хранилищ — куда ложится стейт
- [`05-replication-sharding.md`](05-replication-sharding.md) — соседняя статья: репликация и шардирование выбранных хранилищ, local/global вторичные индексы в распределённой системе
- [`../brief.md`](../brief.md) — бриф: раздел 04 с критерием «умею, если»
- [`../knowledge-base.md`](../knowledge-base.md) — §3 таблица классов и критерии выбора, §3.1 движки (LSM vs B-tree), §2 числа для «влезает/не влезает»
- [`../methodology.md`](../methodology.md) — §2 карточка этапа 4, §4 топ-10 ошибок (№5 и №10 отсюда), §6 протокол тренировок, §7 одностраничная карточка
- [`../classic-designs.md`](../classic-designs.md) — §1 URL shortener, §2 лента (пять хранилищ), §3 мессенджер (conversation_id) — эталоны §7
- [`../materials/ddia-2ed/ch-03-data-models.md`](../materials/ddia-2ed/ch-03-data-models.md) · [`../materials/ddia-2ed/ch-04-storage-retrieval.md`](../materials/ddia-2ed/ch-04-storage-retrieval.md) — источники: полный текст гл. 3–4 DDIA 2-го изд.
- [`../materials/alex-xu-vol1/ch-06-key-value-store.md`](../materials/alex-xu-vol1/ch-06-key-value-store.md) — источник: устройство KV-хранилища (§2, §5)
- Соседние статьи: `06-caching.md` (KV-класс как кэш-слой) · `07-queues-streams.md` (outbox/CDC, конвейеры проекций) · `08-fault-tolerance.md` (отказ проекции vs отказ источника) · `09-consistency.md` (гарантии, которыми платим за выбор)
