3. Нормализация 1NF–3NF
🧭 Введение: зачем нормализация нужна до первых багов
Когда таблицы проектируют «по ощущениям», в них быстро появляются дубли: один и тот же клиент, город или цена живут в десятках строк.
Пока данных мало, это почти незаметно, но при росте продукта начинаются постоянные расхождения и ручные исправления.
Пока данных мало, это почти незаметно, но при росте продукта начинаются постоянные расхождения и ручные исправления.
Нормализация 1NF–3NF — это практический способ убрать лишние повторы и разложить данные так, чтобы каждый факт хранился в одном месте.
В итоге схема становится предсказуемой: обновления безопаснее, отчёты точнее, а сопровождение дешевле.
В итоге схема становится предсказуемой: обновления безопаснее, отчёты точнее, а сопровождение дешевле.
💡 Совет:
Воспринимайте нормализацию не как «теорию для экзамена», а как технику снижения будущих багов.
✅ Вывод:
Нормализация — это базовая защита от дубликатов, противоречий и дорогих исправлений в продакшене.
⚠️ Проблема -> решение
Без нормализации команда часто хранит всё в одной «широкой» таблице: заказ, клиент, товар, менеджер, город, статус, цена.
Из-за этого изменение одного факта требует править много строк, а удаление может случайно стереть важную информацию.
Из-за этого изменение одного факта требует править много строк, а удаление может случайно стереть важную информацию.
Решение — проходить данные через 1NF, 2NF и 3NF:
сначала атомарные поля, затем устранение частичных зависимостей, потом удаление транзитивных зависимостей.
сначала атомарные поля, затем устранение частичных зависимостей, потом удаление транзитивных зависимостей.
🟢 Если совсем просто:
Один факт должен иметь одно место хранения.
🎯 Как понять, что этап прошёл успешно:
Изменение справочного значения делается в одной таблице и сразу корректно отражается во всех связанных записях.
🛠️ Чем помогает и как работает
Нормализация даёт схеме чёткую структуру и убирает «скрытые мины», которые обычно взрываются при росте данных.
Это не про усложнение, а про системное устранение причин аномалий.
Это не про усложнение, а про системное устранение причин аномалий.
🟢 Если совсем просто:
Нормализация делает данные менее хрупкими.
🎯 Как понять, что этап прошёл успешно:
В схеме нет лишних дублей, а логика обновлений и удалений предсказуема.
Чем помогает:
- снижает дублирование данных;
- уменьшает риск противоречивых значений;
- упрощает обновления и аудит изменений;
- делает схему масштабируемой и понятной для команды.
Как это работает:
- Шаг 1: фиксируем сущности и все атрибуты, которые сейчас лежат в «широкой» таблице.
- Шаг 2: приводим данные к 1NF (атомарные поля, без списков в ячейках).
- Шаг 3: определяем ключи и проверяем, от чего функционально зависит каждый атрибут.
- Шаг 4: применяем 2NF и выносим атрибуты, зависящие только от части составного ключа.
- Шаг 5: применяем 3NF и убираем транзитивные зависимости через отдельные справочники.
- Шаг 6: добавляем PK/FK/UNIQUE/CHECK и индексы под ключевые чтения.
- Шаг 7: прогоняем сценарии insert/update/delete и проверяем, что аномалии исчезли.
- Шаг 8: фиксируем результат в миграции и дизайн-заметках.
✅ Вывод:
Нормализация переводит схему из состояния «работает случайно» в состояние «работает по правилам».
📚 Ключевые термины (простыми словами)
Чтобы не запутаться, важно одинаково понимать термины, которые постоянно используются при разборе 1NF–3NF.
🟢 Если совсем просто:
Это словарь, без которого сложно обсуждать зависимости и разбиение таблиц.
🎯 Как понять, что этап прошёл успешно:
Вы можете объяснить любой термин на примере своей схемы.
- 1NF (первая нормальная форма) — все поля атомарны, без массивов/списков в ячейках.
- 2NF (вторая нормальная форма) — нет частичных зависимостей от составного ключа.
- 3NF (третья нормальная форма) — нет транзитивных зависимостей между неключевыми полями.
- Functional Dependency (функциональная зависимость) — значение одного поля однозначно определяет другое.
- Partial Dependency (частичная зависимость) — поле зависит только от части составного ключа.
- Transitive Dependency (транзитивная зависимость) — поле зависит от ключа через другое неключевое поле.
- Anomaly (аномалия) — ошибка модели при вставке, обновлении или удалении данных.
✅ Вывод:
Понимание зависимостей важнее заучивания формулировок нормальных форм.
🗺️ Мини ER-модель (ASCII)
Ниже упрощённый визуальный скелет той же схемы, чтобы быстрее связать 1NF–3NF с реальными таблицами.
🟢 Если совсем просто:
Сначала рисуем связи сущностей, потом детализируем поля и ограничения.
🎯 Как понять, что этап прошёл успешно:
По схеме понятно, где справочники, где транзакционные таблицы и как они связаны.
cities------id (PK)name ▲ │ city_id (FK)customers---------id (PK)full_namecity_id ▲ │ customer_id (FK)orders------id (PK)customer_idcreated_at ▲ │ order_id (FK)order_items products---------- --------order_id (PK, FK) id (PK)product_id (PK, FK) ───► titleqty priceunit_price✅ Вывод:
Даже простая ASCII ER-схема снижает риск ошибок в зависимостях перед написанием SQL.
🧱 1. 1NF: атомарность и отсутствие повторяющихся групп
1NF — первый и самый важный барьер от «грязной» структуры данных.
Здесь мы запрещаем хранить список значений в одном поле и приводим запись к виду «одна ячейка = одно значение».
Здесь мы запрещаем хранить список значений в одном поле и приводим запись к виду «одна ячейка = одно значение».
🟢 Если совсем просто:
В одной ячейке нельзя хранить сразу несколько значений.
🎯 Как понять, что этап прошёл успешно:
Вы не видите полей вроде
item_ids = '1,2,3' или phones = '...;...;...'.Назначение:
Убрать повторяющиеся группы и обеспечить атомарность данных.
Простыми словами:
Каждое поле хранит только один факт, а не список фактов.
Для новичка:
Если вы ставите запятую, чтобы «упаковать» несколько значений в один столбец, это почти всегда нарушение 1NF.
Аналогия:
Это как ячейки в Excel: в каждой должна быть одна единица информации, иначе сортировка и фильтрация ломаются.
Пример:
-- Плохо: список товаров в одной строкеCREATE TABLE orders_raw ( order_id BIGINT PRIMARY KEY, product_ids TEXT, customer_name TEXT); -- Хорошо: отдельная таблица позиций заказаCREATE TABLE order_items ( order_id BIGINT NOT NULL, product_id BIGINT NOT NULL, qty INT NOT NULL CHECK (qty > 0), PRIMARY KEY (order_id, product_id));🔎 Как это происходит на практике:
- Контекст: в исходной таблице есть поля со списками значений.
- Действия: повторяющиеся группы выносят в отдельные строки/таблицы.
- Результат: данные становятся пригодными для корректных JOIN, фильтров и агрегаций.
Характеристики:
- каждое поле атомарно;
- JSON и массивы допустимы для вспомогательных данных (event payload, metadata), но не для ключевых связей модели;
- строки легко валидировать и индексировать.
Когда использовать:
Всегда, это обязательная база перед 2NF и 3NF.
✅ Вывод:
Без 1NF дальнейшая нормализация теряет смысл.
🧩 2. 2NF: убираем частичные зависимости
2NF важна там, где используется составной ключ.
Если неключевое поле зависит только от части такого ключа, оно должно жить в другой таблице.
Если неключевое поле зависит только от части такого ключа, оно должно жить в другой таблице.
В типичном OLTP часто используется суррогатный
id как PK, поэтому 2NF чаще всего проявляется именно в таблицах-связках, например:order_items(order_id, product_id).🟢 Если совсем просто:
Если ключ состоит из двух полей, зависимые данные должны зависеть от обоих, а не только от одного.
🎯 Как понять, что этап прошёл успешно:
В таблице со составным ключом нет столбцов, которые относятся только к одной стороне связи.
Назначение:
Убрать частичные зависимости и сократить дубли справочных данных.
Простыми словами:
Информация о товаре должна храниться в таблице товара, а не дублироваться в каждой позиции заказа.
Для новичка:
Если поле можно определить, зная только
product_id, ему не место в таблице (order_id, product_id).Аналогия:
Это как договор и паспорт: паспортные данные хранятся в карточке человека, а не в каждом договоре с ним.
Пример:
-- Плохо: product_name зависит только от product_idCREATE TABLE order_items_bad ( order_id BIGINT NOT NULL, product_id BIGINT NOT NULL, product_name TEXT NOT NULL, qty INT NOT NULL, PRIMARY KEY (order_id, product_id)); -- Хорошо: справочные атрибуты товара в productsCREATE TABLE products ( id BIGINT PRIMARY KEY, product_name TEXT NOT NULL);🔎 Как это происходит на практике:
- Контекст: таблица связи содержит много дублирующихся описательных полей.
- Действия: поля с частичной зависимостью выносят в отдельную сущность.
- Результат: изменение названия товара делается в одном месте.
Характеристики:
- применима после 1NF;
- критична при составных ключах;
- уменьшает избыточность и update-anomaly.
Когда использовать:
Когда в модели есть таблицы вида
(A_id, B_id, ...) и справочные поля одной стороны.✅ Вывод:
2NF отделяет «данные связи» от «данных одной сущности».
🔗 3. 3NF: убираем транзитивные зависимости
Даже после 2NF в таблице могут оставаться поля, которые зависят от ключа не напрямую, а через другое неключевое поле.
Такие зависимости создают «скрытые дубли» и делают обновления опасными.
Такие зависимости создают «скрытые дубли» и делают обновления опасными.
🟢 Если совсем просто:
Неключевые поля не должны зависеть от других неключевых полей.
🎯 Как понять, что этап прошёл успешно:
Справочные признаки (например, город клиента) вынесены в отдельные таблицы и не дублируются по каждой строке заказа.
Короткая формула для запоминания:
(неключевые атрибуты должны зависеть от ключа, от полного ключа и ни от чего кроме ключа).
the key, the whole key, and nothing but the key(неключевые атрибуты должны зависеть от ключа, от полного ключа и ни от чего кроме ключа).
Назначение:
Убрать транзитивные зависимости и окончательно стабилизировать модель в пределах 3NF.
Простыми словами:
Если
customer_id определяет city_id, то city_name не должен лежать в таблице заказа.Для новичка:
Проверьте: можно ли получить значение поля через другое неключевое поле. Если да — вероятно, нужно выносить.
Аналогия:
Это как хранить название города в паспорте и в каждом билете человека одновременно — рассинхрон почти гарантирован.
Пример:
-- Плохо: city_name транзитивно зависит от customer_idCREATE TABLE orders_bad ( id BIGINT PRIMARY KEY, customer_id BIGINT NOT NULL, city_name TEXT NOT NULL); -- Хорошо: город хранится отдельно и связан ключомCREATE TABLE cities ( id BIGINT PRIMARY KEY, name TEXT NOT NULL UNIQUE); CREATE TABLE customers ( id BIGINT PRIMARY KEY, city_id BIGINT NOT NULL REFERENCES cities(id));🔎 Как это происходит на практике:
- Контекст: в транзакционных таблицах дублируются справочники.
- Действия: неключевые справочные атрибуты выносят в отдельные сущности с PK/FK.
- Результат: изменение справочных значений выполняется централизованно.
Характеристики:
- применима после 2NF;
- убирает цепочки зависимостей внутри одной таблицы;
- снижает риск противоречий в отчётности.
Когда использовать:
Когда замечаете дубли справочников и косвенные зависимости между неключевыми полями.
✅ Вывод:
3NF завершает базовую нормализацию и делает схему устойчивой к изменениям.
🧪 4. Пошаговая декомпозиция: от «широкой таблицы» к 3NF
Главный практический навык — не просто знать определения, а уметь разложить реальную таблицу по шагам.
Для джуна это важнее теоретической дискуссии о «дальнейших формах».
Для джуна это важнее теоретической дискуссии о «дальнейших формах».
🟢 Если совсем просто:
Нормализация — это последовательный алгоритм, а не разовая догадка.
🎯 Как понять, что этап прошёл успешно:
Вы можете показать схему «до/после» и объяснить, какую аномалию устраняет каждый шаг.
Назначение:
Системно преобразовать исходную структуру в 1NF–3NF без потери бизнес-смысла.
Простыми словами:
Мы делаем несколько маленьких, проверяемых шагов вместо одной большой «магической» переделки.
Для новичка:
Работайте итеративно: сначала 1NF, потом 2NF, потом 3NF, и после каждого шага проверяйте данные.
Аналогия:
Это как ремонт квартиры по комнатам: если ломать всё сразу, легко потерять контроль.
Пример:
CREATE TABLE sales_raw ( sale_id BIGINT PRIMARY KEY, customer_name TEXT, customer_city TEXT, product_ids TEXT, product_names TEXT, manager_name TEXT);🔎 Как это происходит на практике:
- Контекст: есть историческая «широкая» таблица из legacy-системы.
- Действия: выделяют сущности
customers,cities,products,sales,sale_items, задают PK/FK. - Результат: схема становится модульной, и каждую сущность можно изменять отдельно.
Характеристики:
- декомпозиция выполняется по зависимостям, а не по «красоте SQL»;
- после каждого шага проверяют число строк и консистентность;
- для миграций готовят сценарий обратной проверки.
Когда использовать:
При рефакторинге legacy-таблиц и при проектировании новых доменов на старте.
✅ Вывод:
Пошаговая декомпозиция — самый безопасный путь к рабочей 3NF-схеме.
🚀 5. Баланс нормализации и производительности
Частая ошибка — считать, что после нормализации «производительность испортится».
На практике проблема обычно не в нормализации, а в отсутствии индексов и понимания реальных сценариев чтения.
На практике проблема обычно не в нормализации, а в отсутствии индексов и понимания реальных сценариев чтения.
🟢 Если совсем просто:
Нормализуем данные, а производительность обеспечиваем индексами и правильными запросами.
🎯 Как понять, что этап прошёл успешно:
Ключевые запросы читают данные быстро, а схема остаётся без лишних дублей.
Базовое правило:
Индексируйте FK-поля по умолчанию, если таблицы участвуют в регулярных JOIN и фильтрации.
Назначение:
Показать, что 3NF и скорость чтения не противоречат друг другу при корректном проектировании.
Простыми словами:
Сначала делаем правильную модель данных, потом «подкручиваем» чтение индексами.
Для новичка:
Не денормализуйте рано: сначала измерьте реальную проблему через планы выполнения и метрики.
Аналогия:
Это как правильная карта города и быстрые дороги: карта отвечает за логику, дороги — за скорость.
Пример:
CREATE INDEX idx_orders_customer_id ON orders(customer_id); CREATE INDEX idx_order_items_order_id ON order_items(order_id); SELECT o.id, c.full_name, SUM(oi.qty * oi.price) AS totalFROM orders oJOIN customers c ON c.id = o.customer_idJOIN order_items oi ON oi.order_id = o.idWHERE o.customer_id = 42GROUP BY o.id, c.full_name;🔎 Как это происходит на практике:
- Контекст: после нормализации запросы стали более «JOIN-ориентированными».
- Действия: команда индексирует FK и горячие фильтры, проверяет
EXPLAIN ANALYZE. - Результат: схема остаётся чистой, а скорость чтения соответствует SLA.
Характеристики:
- индексы на FK обычно обязательны при росте данных;
- оптимизация делается по метрикам, а не по ощущениям;
- денормализация — осознанное исключение, а не стартовая стратегия.
Когда использовать:
После приведения модели к 3NF и появления измеримой нагрузки на чтение.
✅ Вывод:
Нормализация и производительность совместимы, если проектировать схему под реальные запросы.
⚖️ Сравнение 1NF, 2NF и 3NF
Каждая форма решает свой класс проблем, поэтому важно понимать разницу, а не «перепрыгивать» этапы.
Ниже короткая таблица для быстрого повторения.
Ниже короткая таблица для быстрого повторения.
🟢 Если совсем просто:
1NF убирает списки в ячейках, 2NF — частичные зависимости, 3NF — транзитивные.
🎯 Как понять, что этап прошёл успешно:
Вы можете на живом примере объяснить, какую проблему устраняет каждая форма.
| Нормальная форма | Что запрещает | Что устраняет | Типичный результат |
|---|---|---|---|
| 1NF | списки/массивы в поле | часть insert/update проблем | атомарные поля |
| 2NF | зависимость от части составного ключа | дубли справочных полей в таблицах-связках | чистые таблицы связей |
| 3NF | зависимость неключевых полей друг от друга | транзитивные дубли справочников | стабильные справочные связи |
✅ Вывод:
Последовательный переход 1NF -> 2NF -> 3NF даёт предсказуемую и поддерживаемую модель данных.
📌 Must-know факты
Это минимальный набор, который нужен для практической работы и собеседований по теме нормализации.
Если эти пункты не держать в голове, ошибки в модели почти неизбежны.
Если эти пункты не держать в голове, ошибки в модели почти неизбежны.
🟢 Если совсем просто:
Must-know — это «чек-лист выживания» при проектировании таблиц.
🎯 Как понять, что этап прошёл успешно:
Вы можете пройтись по своему DDL и подтвердить каждый пункт конкретным примером.
- 1NF обязательна: никаких списков и повторяющихся групп в одном поле.
- 2NF актуальна при составных ключах: неключевые атрибуты должны зависеть от полного ключа.
- 3NF убирает транзитивные зависимости между неключевыми атрибутами.
- Нормализация решает аномалии insert/update/delete, а не «делает схему красивой».
- PK/FK/UNIQUE/CHECK закрепляют результат нормализации на уровне БД.
- После нормализации критичны индексы на FK и частых фильтрах.
- Денормализация допустима только после измерений и с документированным обоснованием.
✅ Вывод:
Если игнорировать must-know по нормализации, данные быстро становятся противоречивыми.
🧨 Частые мифы
Вокруг нормализации много мифов, из-за которых команды либо переусложняют модель, либо отказываются от неё слишком рано.
Ниже самые частые ошибки мышления.
Ниже самые частые ошибки мышления.
🟢 Если совсем просто:
Плохая модель данных почти всегда «начинается с удобного мифа».
🎯 Как понять, что этап прошёл успешно:
Вы можете на практике опровергнуть каждый миф и показать рабочую альтернативу.
❌ Миф: Нормализация нужна только для больших корпораций.
✅ Как правильно: Даже маленький проект выигрывает от 1NF–3NF, потому что баги из-за дублей появляются очень рано.
📎 Почему это важно: Чем раньше убрать аномалии, тем меньше переделок в продакшене.
❌ Миф: 3NF всегда делает систему медленной.
✅ Как правильно: Скорость зависит от запросов и индексов; 3NF и производительность совместимы.
📎 Почему это важно: Отказ от нормализации ради «скорости» часто создаёт ещё более дорогие проблемы.
❌ Миф: Если есть ORM, нормализация не нужна.
✅ Как правильно: ORM не отменяет правила хранения данных и не устраняет аномалии модели.
📎 Почему это важно: Неправильная схема остаётся неправильной независимо от фреймворка.
❌ Миф: Денормализация всегда лучше, потому что меньше JOIN.
✅ Как правильно: Денормализация — инструмент оптимизации после измерений, а не базовый дизайн.
📎 Почему это важно: Преждевременная денормализация почти всегда увеличивает число конфликтов данных.
❓ Часто спрашивают на собеседованиях
Эти вопросы почти всегда появляются в блоке SQL/Data Modeling на junior/middle интервью.
Отвечайте через примеры, а не только определениями.
Отвечайте через примеры, а не только определениями.
🟢 Если совсем просто:
Интервьюер проверяет, умеете ли вы убирать аномалии в реальной схеме.
🎯 Как понять, что этап прошёл успешно:
Вы можете объяснить ответы на основе одной предметной области (например, заказы/позиции/клиенты).
❓ Вопрос: Что именно гарантирует 1NF?
✅ Ответ: 1NF гарантирует атомарные поля и отсутствие повторяющихся групп; каждый столбец хранит одно значение на ячейку.
❓ Вопрос: Когда проверка 2NF действительно обязательна?
✅ Ответ: Когда есть составной ключ; нужно убедиться, что неключевые поля зависят от полного ключа, а не от его части.
❓ Вопрос: Как распознать транзитивную зависимость для 3NF?
✅ Ответ: Если неключевое поле можно определить через другое неключевое поле, значит зависимость транзитивная и поле нужно выносить.
❓ Вопрос: Почему нормализация снижает update-anomaly?
✅ Ответ: Потому что каждый факт хранится в одном месте, и его изменение не требует массовых правок дубликатов.
❓ Вопрос: Что делать, если после нормализации запросы стали сложнее?
✅ Ответ: Анализировать реальные запросы, добавлять индексы и оптимизировать JOIN, а не сразу ломать модель денормализацией.
❓ Вопрос: Когда денормализация допустима?
✅ Ответ: Когда есть измеримая проблема производительности, подтверждённая метриками, и есть план поддержания консистентности.
❓ Вопрос: Как объяснить разницу 2NF и 3NF в одной фразе?
✅ Ответ: 2NF убирает зависимости от части составного ключа, 3NF — зависимости неключевых полей друг от друга.
❓ Вопрос: Что важнее при миграции legacy-таблицы: идеальная теория или пошаговый план?
✅ Ответ: Пошаговый план с проверкой данных после каждого шага; иначе риск потери данных и бизнес-остановки слишком высок.
🚫 Типичные ошибки
При нормализации чаще всего ошибаются не в синтаксисе SQL, а в логике зависимостей.
Ниже ошибки, которые стоит проверять на каждом ревью схемы.
Ниже ошибки, которые стоит проверять на каждом ревью схемы.
🟢 Если совсем просто:
Если не проверить зависимости, «формально нормальная» схема всё равно может быть плохой.
🎯 Как понять, что этап прошёл успешно:
Вы прошли по каждому пункту и можете объяснить, почему его не нарушаете.
Ошибка 1: считать 1NF «достаточной нормализацией»
❌ Неправильно:
Остановиться на атомарных полях и не проверять частичные/транзитивные зависимости.
✅ Правильно:
После 1NF обязательно проверить 2NF и 3NF по фактическим зависимостям.
Почему:
Основные дубли часто остаются именно после «незавершённой» нормализации.
Ошибка 2: тащить справочные поля в таблицы связей
❌ Неправильно:
Хранить
product_name или customer_city в таблице позиций заказа.✅ Правильно:
Держать справочные поля в своих сущностях и использовать FK.
Почему:
Это классический источник частичных и транзитивных зависимостей.
Ошибка 3: игнорировать insert/delete anomalies
❌ Неправильно:
Оценивать модель только по одному
SELECT, не проверяя вставку и удаление.✅ Правильно:
Всегда прогонять сценарии insert/update/delete до фиксации схемы.
Почему:
Аномалии обычно проявляются именно в операциях записи, а не в простом чтении.
Ошибка 4: преждевременная денормализация «для скорости»
❌ Неправильно:
Смешивать сущности до измерений, чтобы «уменьшить количество JOIN».
✅ Правильно:
Сначала нормализовать, потом оптимизировать по метрикам и планам запросов.
Почему:
Без измерений денормализация чаще создаёт проблемы, чем решает.
Ошибка 5: не документировать зависимости и этапы разбиения
❌ Неправильно:
Оставлять схему без объяснения, почему таблица была разделена именно так.
✅ Правильно:
Фиксировать в design-notes исходные зависимости, шаги 1NF–3NF и итоговые правила.
Почему:
Без документации команда быстро теряет контекст и возвращается к прежним ошибкам.
✅ Best Practices
Ниже практики, которые помогают держать нормализацию «живой» в реальном проекте, а не только в учебном примере.
Используйте их как чек-лист перед каждой миграцией схемы.
Используйте их как чек-лист перед каждой миграцией схемы.
🟢 Если совсем просто:
Best Practices помогают не откатываться обратно в «широкие» таблицы.
🎯 Как понять, что этап прошёл успешно:
Схема проходит ревью и выдерживает типовые сценарии записи/чтения без аномалий.
- Начинайте с зависимостей данных, а не с готового SQL.
- Явно отмечайте, какой шаг относится к 1NF, 2NF и 3NF.
- Любое справочное поле держите в таблице его сущности.
- Проверяйте аномалии insert/update/delete на тестовых данных.
- Добавляйте ограничения и индексы сразу после декомпозиции.
- Индексируйте FK-поля как стандартный шаг после создания связей.
- Документируйте причины денормализации, если она реально нужна.
- Делайте миграции небольшими и проверяемыми после каждого шага.
🧾 Заключение
Нормализация 1NF–3NF — это практический инструмент управления качеством данных, а не академическое упражнение.
Если пройти эти шаги последовательно, схема становится устойчивой к росту продукта и изменениям требований.
Если пройти эти шаги последовательно, схема становится устойчивой к росту продукта и изменениям требований.
Ключевые мысли
- 1NF устраняет неатомарные поля и повторяющиеся группы.
- 2NF убирает частичные зависимости от составного ключа.
- 3NF убирает транзитивные зависимости между неключевыми полями.
- Индексы и ограничения закрепляют результат нормализации в продакшене.
Хорошая нормализация — это когда данные легко менять, сложно сломать и просто объяснить новой команде.