Нормализация баз данных: 1НФ, 2НФ, 3НФ, Бойса–Кодда

Зачем нужна нормализация? 🛠️

Нормализация — это процесс организации данных в базе так, чтобы минимизировать дублирование и аномалии при обновлении. Представьте, что у вас есть таблица Orders с полями:

CREATE TABLE Orders (
    order_id INT,
    customer_name VARCHAR(100),
    customer_phone VARCHAR(20),
    product_name VARCHAR(100),
    product_price DECIMAL(10, 2),
    quantity INT
);

Проблема: если клиент закажет 10 раз, его имя и телефон повторятся 10 раз. При смене номера придётся обновлять все записи!

👉 Цель нормализации: разбить данные на логические таблицы, где каждая хранит только то, что действительно нужно.


Первая нормальная форма (1НФ) ✅

Правило: Все атрибуты должны быть атомарными (неделимыми), а таблица — не содержать повторяющихся групп.

❌ Плохой пример (список товаров в одной ячейке):

order_id products
1 Книга, Футболка

✅ Исправленный вариант:

CREATE TABLE Orders_1NF (
    order_id INT,
    product_name VARCHAR(100)  -- Один товар на строку
);

Что проверить: - Нет столбцов с множественными значениями (например, phone1, phone2). - Нет повторяющихся групп данных.


Вторая нормальная форма (2НФ) 🔍

Правило: Таблица должна быть в 1НФ + каждый неключевой атрибут зависит от всего первичного ключа.

Пример проблемы в таблице OrderDetails:

CREATE TABLE OrderDetails (
    order_id INT,
    product_id INT,
    product_name VARCHAR(100),  -- Зависит только от product_id!
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

🚨 product_name зависит только от product_id, а не от всей связки (order_id, product_id).

✅ Решение — разбить на две таблицы:

CREATE TABLE Products (
    product_id INT PRIMARY KEY,
    product_name VARCHAR(100)
);

CREATE TABLE OrderDetails_2NF (
    order_id INT,
    product_id INT,
    quantity INT,
    FOREIGN KEY (product_id) REFERENCES Products(product_id)
);

Третья нормальная форма (3НФ) 🎯

Правило: Таблица должна быть в 2НФ + не должно быть транзитивных зависимостей (когда атрибут зависит от другого неключевого атрибута).

Пример «запаха» в таблице Orders:

CREATE TABLE Orders (
    order_id INT PRIMARY KEY,
    customer_id INT,
    customer_zip_code VARCHAR(10),  -- Зависит от customer_id, а не от order_id
    order_date DATE
);

💡 customer_zip_code зависит от customer_id, который сам не является первичным ключом.

✅ Нормализованный вариант:

CREATE TABLE Customers (
    customer_id INT PRIMARY KEY,
    customer_zip_code VARCHAR(10)
);

CREATE TABLE Orders_3NF (
    order_id INT PRIMARY KEY,
    customer_id INT,
    order_date DATE,
    FOREIGN KEY (customer_id) REFERENCES Customers(customer_id)
);

Нормальная форма Бойса–Кодда (BCNF) 🏆

Правило: Усиленная 3НФ, где любой определяющий атрибут (даже не входящий в первичный ключ) должен быть потенциальным ключом.

Сложный случай — таблица Teaching:

CREATE TABLE Teaching (
    professor_id INT,
    subject VARCHAR(100),
    classroom VARCHAR(50),
    PRIMARY KEY (professor_id, subject)
);

Предположим, что:

  • Один профессор ведёт один предмет.
  • Один предмет может быть только в одной аудитории.

🚨 Проблема: classroom зависит от subject (который не является ключом сам по себе).

✅ Решение по BCNF:

CREATE TABLE Subjects (
    subject VARCHAR(100) PRIMARY KEY,
    classroom VARCHAR(50)
);

CREATE TABLE Teaching_BCNF (
    professor_id INT,
    subject VARCHAR(100),
    PRIMARY KEY (professor_id, subject),
    FOREIGN KEY (subject) REFERENCES Subjects(subject)
);

Когда остановиться? 🛑

Нормализация решает проблемы, но избыточная нормализация усложняет запросы. Иногда денормализация (например, дублирование данных для скорости) — осознанный выбор.

Практический совет:

  • Начинайте с 3НФ для большинства проектов.
  • Переходите к BCNF, если видите явные аномалии обновления.
  • Для аналитики (OLAP) иногда лучше звездообразная схема.
Скрыть рекламу навсегда

🎥 YouTube: программирование простым языком

Канал, где я спокойно и по шагам объясняю сложные темы — без заумных терминов и лишней теории.

Подходит, если раньше «не заходило», но хочется наконец понять.

▶️ Смотреть курсы на YouTube