Зависимости между данными, ошибки повторения и осознанное хранение итогов
На прошлом уроке мы разнесли товары, пользователей и заказы по таблицам. Теперь разберём, почему такое разделение уменьшает число ошибок.
Нормализация — способ разместить каждый самостоятельный факт там, где он хранится один раз. Цель не в том, чтобы получить как можно больше таблиц, а в том, чтобы одно изменение не требовало вручную исправлять множество строк.
Представим таблицу, где в каждой строке заказа повторяются данные клиента и организации:
| order_id | user_id | org_id | org_name | plan | |
|---|---|---|---|---|---|
| 101 | 7 | anna@example.ru | 3 | Ромашка | pro |
| 102 | 7 | anna@example.ru | 3 | Ромашка | pro |
Если организация сменит тариф, поле plan придётся менять во всех её заказах.
Пропущенная строка сохранит старое значение, хотя речь идёт об одном факте.
Здесь действуют зависимости:
order_id → user_id;user_id → org_id;org_id → plan.Запись X → Y читается так: «для одного значения X возможно только одно
значение Y». Это называется функциональной зависимостью.
Повторение одного факта в разных строках приводит к трём типичным проблемам.
Эти проблемы часто называют аномалиями обновления, вставки и удаления. Решение
для примера — отдельные таблицы organizations, app_users и orders,
связанные внешними ключами. Название и тариф организации тогда хранятся в одной
строке organizations.
Нормальная форма — набор правил, помогающий находить неправильные зависимости. Для начала достаточно понимать их смысл.
order_items, а не в столбцах product_1, product_2.Не нужно заучивать названия перед практикой. Сначала спрашивайте: «Если факт изменится, в скольких местах его придётся исправить?»
В позиции заказа хранится unit_price — цена на момент покупки. В таблице
товаров хранится текущая цена. Значения могли совпасть при создании заказа, но
они отвечают на разные вопросы, поэтому это два разных факта.
Осознанное добавление повторного или заранее вычисленного значения ради скорости называют денормализацией. Например, можно сохранить дневную сумму продаж, чтобы не пересчитывать миллионы заказов для каждого отчёта.
Перед денормализацией нужно ответить:
Периодическое сравнение производного значения с исходными данными называют
сверкой (reconciliation). Только один механизм должен владеть обновлением:
не стоит поручать одну сумму одновременно триггеру, приложению и фоновой задаче.
Массив подходит для небольшого набора простых значений без собственных свойств.
Например, у записи могут быть метки ['new', 'gift'].
Если у элемента есть автор, дата, порядок, права или ссылка на другую таблицу, нужна таблица связи. Товар заказа имеет количество и цену, поэтому список идентификаторов товаров в массиве потерял бы важные сведения.
JSONB и массивы полезны, но не отменяют проектирование связей.
В лаборатории 03 вы начнёте с широкой таблицы заказов, выпишете зависимости и разделите её до 3NF. Затем добавите один сохранённый итог и SQL-запрос для его сверки.
После работы объясните своими словами:
Подробнее: ограничения и связи между таблицами.
Вопросы ещё не добавлены
Вопросы для этой подтемы ещё не добавлены.
Далее: Типы данных: какие значения можно хранить