Что такое нормализация в целом

Нормализация - это процесс приведения структуры таблиц к формам, которые уменьшают избыточность данных и устраняют аномалии.

Под аномалиями понимают типовые проблемы:

  • аномалия обновления - одно и то же значение нужно менять в нескольких местах;
  • аномалия вставки - невозможно добавить данные без добавления лишних полей;
  • аномалия удаления - удаление одной записи приводит к потере других данных.

Нормальные формы вводят ограничения, которые шаг за шагом устраняют эти проблемы.


Первая нормальная форма (1NF)

Таблица находится в первой нормальной форме (1NF), если:

  • все значения атомарны (неделимы);
  • в каждой ячейке хранится ровно одно значение;
  • отсутствуют повторяющиеся группы и массивы.

Проще говоря: никаких списков, массивов и "значение1, значение2, значение3" в одном поле.

- Плохой пример (не 1NF)

Orders
---------------------------------
order_id | customer | products
---------------------------------
1 | Ivan | apple, banana, orange

Проблемы:

  • поле products содержит несколько значений;
  • невозможно нормально сделать JOIN;
  • сложно фильтровать и индексировать.

- Исправленный вариант (1NF)

Orders
------------------------
order_id | customer
------------------------
1 | Ivan


OrderProducts
------------------------
order_id | product
------------------------
1 | apple
1 | banana
1 | orange

Теперь:

  • каждое значение атомарно;
  • данные легко связываются;
  • структура масштабируется.

1NF - это база. Если таблица не в 1NF, дальше идти бессмысленно.


Вторая нормальная форма (2NF)

Таблица находится во второй нормальной форме (2NF), если:

  • она уже в 1NF;
  • все неключевые атрибуты зависят от всего первичного ключа, а не от его части.

Это правило имеет смысл только для таблиц с составным первичным ключом.

- Плохой пример (1NF, но не 2NF)

OrderItems
---------------------------------------------
order_id | product_id | product_name | price
---------------------------------------------
1 | 10 | Apple | 2.00
1 | 11 | Banana | 1.50

Предположим, первичный ключ - (order_id, product_id).

Проблема:

  • product_name и price зависят только от product_id,
  • но хранятся в таблице, зависящей от заказа.

Аномалии:

  • при изменении цены нужно обновлять множество строк;
  • возможны рассинхронизации данных.

- Исправленный вариант (2NF)

Products
------------------------------
product_id | product_name | price
------------------------------
10 | Apple | 2.00
11 | Banana | 1.50


OrderItems
------------------------------
order_id | product_id
------------------------------
1 | 10
1 | 11

Теперь:

  • атрибуты продукта зависят только от product_id;
  • таблица OrderItems описывает только связь заказа и продукта.

2NF отделяет справочные данные от данных отношений.


Третья нормальная форма (3NF)

Таблица находится в третьей нормальной форме (3NF), если:

  • она уже в 2NF;
  • неключевые атрибуты не зависят друг от друга;
  • нет транзитивных зависимостей.

Проще: неключевое поле не должно определять другое неключевое поле.

- Плохой пример (2NF, но не 3NF)

Users
-------------------------------------------
user_id | name | city | city_country
-------------------------------------------
1 | Ali | Baku | Azerbaijan

Проблема:

  • city_country зависит от city,
  • а city - не ключ.

Аномалии:

  • при ошибке в названии страны ошибка дублируется;
  • при переименовании города нужно менять связанные поля.

- Исправленный вариант (3NF)

Cities
-------------------------
city_id | city | country
-------------------------
1 | Baku | Azerbaijan


Users
-------------------------
user_id | name | city_id
-------------------------
1 | Ali | 1

Теперь:

  • каждое поле зависит только от ключа своей таблицы;
  • данные не дублируются;
  • схема становится устойчивой к изменениям.

3NF - самая популярная и практичная форма в реальных проектах.


Нужно ли всегда доходить до 3NF?

В большинстве случаев - да.

Но важно понимать:

  • нормализация - не религия;
  • иногда допустима осознанная денормализация ради производительности;
  • денормализация должна быть контролируемой, а не случайной.

Типичный подход в продакшене: сначала проектируем схему в 3NF, потом точечно денормализуем узкие места.


Source: Orkhan Alishov's notes