Что такое нормализация базы данных: 1NF, 2NF, 3NF?

JuniorPostgreSQL · Backend·Обновлено 22 августа 2026
Коротко
Нормализация — это процесс разбиения таблиц на более мелкие для устранения избыточности и аномалий данных. 1NF требует атомарности значений в ячейках, 2NF убирает частичные зависимости от составного ключа, а 3NF устраняет транзитивные зависимости неключевых атрибутов друг от друга.

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

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

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

Таблица находится в 1NF, если выполняются условия:

  • каждая ячейка содержит атомарное (неделимое) значение, а не список или вложенную структуру;
  • нет повторяющихся групп однотипных столбцов (например, phone1, phone2, phone3);
  • у каждой строки есть уникальный идентификатор — первичный ключ;
  • значения в столбце имеют один тип.

Пример нарушения 1NF — хранение нескольких телефонов клиента в одной строке через запятую. Решение — вынести телефоны в отдельную таблицу с внешним ключом на клиента.

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

Таблица находится в 2NF, если она уже в 1NF и все неключевые атрибуты полностью зависят от всего составного первичного ключа, а не только от его части. Проблема актуальна только для таблиц с составным ключом.

Пример: таблица orderitems(orderid, productid, productname, quantity) с составным ключом (orderid, productid). Атрибут productname зависит только от productid, а не от всего ключа целиком — это частичная зависимость, нарушающая 2NF. Решение — вынести productname в отдельную таблицу products, оставив в orderitems только product_id.

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

Таблица находится в 3NF, если она уже в 2NF и не содержит транзитивных зависимостей — то есть неключевые атрибуты зависят только напрямую от первичного ключа, а не друг от друга.

Пример: таблица employees(id, departmentid, departmentname). Здесь departmentname зависит от departmentid, а departmentid — от id сотрудника, то есть departmentname зависит от id транзитивно, через departmentid. Решение — вынести departmentid и department_name в отдельную таблицу departments и связать её через внешний ключ.

Мнемоника

Удобно запомнить формулировку Билла Кента: "каждый неключевой атрибут должен зависеть от ключа, от всего ключа и только от ключа".

Практическая польза в PostgreSQL

Правильно нормализованные таблицы с внешними ключами и ограничениями UNIQUE/NOT NULL позволяют PostgreSQL гарантировать целостность данных на уровне схемы, а не приложения, и избегают ситуаций, когда одно и то же значение (например, название отдела) нужно синхронно обновлять в десятках строк.

Когда денормализуют осознанно

На практике для аналитических запросов или высоконагруженного чтения иногда сознательно денормализуют данные (например, дублируют department_name в employees), чтобы избежать JOIN. Это компромисс между скоростью чтения и риском рассинхронизации данных, и junior-кандидату важно понимать, что 3NF — это база, от которой можно осознанно отступать, а не догма.

Что хочет услышать интервьюер

Кандидат объясняет, что нормализация уменьшает дублирование данных и предотвращает аномалии вставки/обновления/удаления

Кандидат формулирует ключевое отличие каждой формы своими словами, а не просто цитирует определение

Кандидат приводит пример таблицы, нарушающей 2NF или 3NF, и показывает, как её разбить

Кандидат понимает, что 2NF актуальна только при составном первичном ключе

Кандидат может рассуждать о компромиссах между нормализацией и производительностью (денормализация)

Пример: Нарушение 2NF и его исправление

-- Нарушение 2NF: product_name зависит только от product_id,
-- а не от всего составного ключа (order_id, product_id)
CREATE TABLE order_items (
    order_id INT,
    product_id INT,
    product_name TEXT,
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

-- Исправление: выносим product_name в отдельную таблицу
CREATE TABLE products (
    product_id SERIAL PRIMARY KEY,
    product_name TEXT NOT NULL
);

CREATE TABLE order_items (
    order_id INT,
    product_id INT REFERENCES products(product_id),
    quantity INT,
    PRIMARY KEY (order_id, product_id)
);

Пример: Нарушение 3NF и его исправление

-- Нарушение 3NF: department_name зависит от department_id,
-- а не напрямую от первичного ключа id
CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    full_name TEXT NOT NULL,
    department_id INT,
    department_name TEXT
);

-- Исправление: выносим отдел в отдельную таблицу
CREATE TABLE departments (
    department_id SERIAL PRIMARY KEY,
    department_name TEXT NOT NULL
);

CREATE TABLE employees (
    id SERIAL PRIMARY KEY,
    full_name TEXT NOT NULL,
    department_id INT REFERENCES departments(department_id)
);

Типичные ошибки

Путают 2NF и 3NF или не могут объяснить разницу между частичной и транзитивной зависимостью

Считают, что 1NF нарушается только массивами, забывая про повторяющиеся группы столбцов

Не приводят конкретный пример таблицы, ограничиваясь абстрактными формулировками

Утверждают, что нормализация всегда улучшает производительность, не упоминая цену JOIN'ов

Не связывают составной первичный ключ с условием применимости 2NF

Лучшие курсы по теме

изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Node.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее