3NF vs star vs One Big Table: когда что выбирать
Trade-offs read perf / write complexity / storage для OLTP, OLAP и аналитики. Как мигрировать между моделями без переписывания клиентов.
Помоги выбрать модель данных для workload: {{workload}}. Размер: {{data_size}}. Платформа: {{warehouse}}.
Три подхода
3NF (нормализация до третьей формы)
Каждый факт хранится в одном месте. Связи через FK.
- Плюсы: нет аномалий обновления, минимум места, целостность через constraints.
- Минусы: аналитический запрос требует 8 JOIN'ов, оптимизатор иногда ошибается.
- Когда: OLTP, источник транзакций, любая запись > чтение в 10×. Postgres/MySQL.
Star schema (Kimball)
Денормализация на уровне измерений. Факт-таблицы тонкие, dim'ы плоские.
- Плюсы: аналитические запросы простые (1 факт + N dims), BI-инструменты понимают, селективные индексы работают.
- Минусы: требует ETL для поддержания, аномалии при обновлении dim надо разруливать SCD.
- Когда: классическое DWH, BI-отчёты, mixed workload. Redshift, Synapse, Postgres.
One Big Table (OBT)
Полная денормализация: всё в одной wide-таблице с сотнями колонок.
- Плюсы: zero JOIN'ов, колоночные движки сжимают эффективно, любой запрос — линейное сканирование.
- Минусы: обновление атрибута dim — переписать миллионы строк, схема жёсткая, дубликат данных огромный.
- Когда: аналитика на BigQuery/Snowflake/Clickhouse, immutable события (логи, телеметрия), append-only нагрузка.
Таблица решений
| Критерий | 3NF | Star | OBT | | Write QPS | Высокий | Средний | Низкий (batch) | | Read complexity | Высокая (много JOIN) | Средняя | Низкая | | Storage cost | Минимум | 2-3× | 5-20× | | Schema flexibility | Высокая | Средняя | Низкая (миграция = переписать) | | Аномалии обновления | Защищено | SCD управляет | Дубликаты | | Подходит для BI | Плохо | Идеально | Хорошо | | Подходит для ad-hoc | Плохо | Средне | Идеально |
Эвристики выбора
- Write-heavy + транзакции → 3NF в OLTP
- Read-heavy + регулярные отчёты → Star в DWH
- Append-only events + ad-hoc analytics → OBT в колоночном движке
- Mixed → 3NF source + Star/OBT marts через ELT
Trade-offs, о которых забывают
- Колоночные движки меняют арифметику. JOIN дорогой, но сжатие OBT экономит I/O. Замерь, не теоретизируй.
- SCD на OBT — кошмар. История через event-time + denorm snapshot колонки, без UPDATE.
- Запись в OBT делается batch'ами через MERGE/INSERT OVERWRITE, не построчно.
- 3NF в OLAP работает на маленьких объёмах (≤100GB), на больших — JOIN'ы выходят из RAM.
Migration patterns
3NF → Star:
- Шаг 1: identify business processes (Kimball bus matrix)
- Шаг 2: built marts as views поверх 3NF
- Шаг 3: материализовать views по мере роста latency
- Шаг 4: переключить клиентов; держать 3NF как source of truth
Star → OBT:
- Шаг 1:
SELECT fact.*, dim1.*, dim2.* FROM fact JOIN dimsматериализовать в новую таблицу - Шаг 2: pre-aggregate по самой частой грануляции
- Шаг 3: версионировать схему (v1, v2 параллельно)
- Шаг 4: deprecate star после миграции дашбордов
Anti-patterns
- ❌ Денормализовать в OLTP «для скорости отчётов» — обновление одного customer.name пишет в 10M строк
- ❌ Хранить OLAP-данные в 3NF без materialised views — каждый дашборд = пересчёт с диска
- ❌ OBT на платформе с дорогим storage (Snowflake compute), хотя partition pruning не работает — счёт улетит
- ❌ Сравнивать read perf 3NF vs Star на пустой БД — план меняется на реальных объёмах
- ❌ Миграция «big bang» вместо параллельной работы — клиенты сломаются, откатываться некуда
Dimensional modeling по Кимбаллу: факты и измерения
Звезда vs снежинка, типы факт-таблиц, conformed/role-playing/junk-измерения, выбор грануляции и где ломаются новички.
Slowly Changing Dimensions: Type 1/2/3/6 без боли
Когда что выбирать, что считается «изменением», как влияет на запросы и размер БД, и как мигрировать без переписывания витрин.
Data contracts: producer ↔ consumer без сюрпризов
Schema versioning, политика breaking changes, валидация в pipeline, choice block vs warn, Avro/Protobuf/JSON Schema на практике.