Нормализация и денормализация
↑ 1.1 Реляционная модель и SQL · ← Предыдущая · → Следующая
Зачем это на собесе
Проверяют, понимаете ли вы, зачем нормализуют и почему иногда сознательно нарушают нормальные формы.
Аномалии в плохой схеме
Таблица orders(order_id, customer_name, customer_phone, product, price):
- аномалия вставки: нельзя добавить клиента без заказа;
- аномалия обновления: телефон клиента хранится в каждом заказе, легко получить расхождения;
- аномалия удаления: удалив последний заказ, теряем клиента.
Нормальные формы
| НФ | Условие | Пример нарушения |
|---|---|---|
| 1НФ | значения атомарны, нет повторяющихся групп | столбец phones = '111, 222' |
| 2НФ | 1НФ + нет частичных зависимостей от части составного ключа | (order_id, product_id) → product_name зависит только от product_id |
| 3НФ | 2НФ + нет транзитивных зависимостей | zip → city, а ключ — user_id |
| BCNF | каждая детерминанта — потенциальный ключ | усиленная 3НФ |
| 4НФ и выше | многозначные зависимости и др. | применяют редко |
Запоминалка: «данные зависят от ключа, от всего ключа и ни от чего, кроме ключа».
Пример
-- до: всё в одной таблице
orders(order_id, customer_email, customer_city, product_name, product_price, qty)
-- после (3НФ)
customers(id, email, city)
products(id, name, price)
orders(id, customer_id)
order_items(order_id, product_id, qty, price_at_order)Обратите внимание на price_at_order: цена на момент заказа — это исторический факт, а не дубль; менять её при обновлении прайса нельзя.
Денормализация
Осознанное нарушение нормальных форм ради скорости чтения.
| Приём | Пример | Цена |
|---|---|---|
| Дублирование поля | orders.customer_name для списка без JOIN | рассинхронизация |
| Счётчики | posts.comments_count | обновление при каждом изменении |
| Материализованные агрегаты | сводные таблицы, materialized view | обновление и задержка |
| JSONB-снимок | адрес доставки на момент заказа | сложность запросов |
| Хранилище для аналитики | звезда, снежинка | отдельная модель |
Поддержка согласованности: транзакции, триггеры, пересчёт в фоне, события.
Когда что
- OLTP: нормализуем до 3НФ, денормализуем точечно по измеренным узким местам;
- OLAP: денормализованные широкие таблицы, схемы «звезда»;
- документные БД — данные, читаемые вместе, хранят вместе.
Вопросы с ответами
Что такое 3НФ простыми словами?
Каждый неключевой столбец зависит только от первичного ключа, а не от другого неключевого столбца.
Когда денормализация оправдана?
Когда измерено, что JOIN или агрегаты стали узким местом, и вы готовы поддерживать согласованность дублирующихся данных.
Почему хранить
price_at_orderв позиции заказа не нарушает нормализацию?Это не копия текущей цены, а факт покупки на момент заказа; он не должен меняться при изменении прайс-листа.