# Нормализация

> Процесс проектирования схемы реляционной базы данных, устраняющий дублирование и аномалии обновления путём разбиения таблиц по нормальным формам (1НФ, 2НФ, 3НФ, НФБК); денормализация — обратный шаг ради скорости чтения.

Источник: https://llmdocs.ru/wiki/normalization/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **Автор теории**: Эдгар Кодд (1970–1971)
- **Основные формы**: 1НФ, 2НФ, 3НФ, нормальная форма Бойса — Кодда (НФБК)
- **Высшие формы**: 4НФ (Фейгин, 1977), 5НФ (1979), 6НФ
- **Цель**: устранить дублирование и аномалии вставки, обновления, удаления
- **Ключевое понятие**: функциональная зависимость
- **Обратный процесс**: денормализация
**Нормализация** — процесс проектирования схемы [реляционной базы данных](https://llmdocs.ru/wiki/relational-database.md), при котором таблицы разбиваются так, чтобы каждый факт хранился ровно в одном месте. Это устраняет дублирование данных и связанные с ним **аномалии**: когда изменение приходится делать в нескольких местах, а забытое место оставляет базу в противоречивом состоянии. Уровни нормализованности называются **нормальными формами**; теорию заложил Эдгар Кодд в 1970–1971 годах.[1]

Обратный шаг — **денормализация** — сознательное дублирование данных ради скорости чтения.

## Проблема: аномалии

Рассмотрим таблицу заказов, в которой всё хранится вместе:

| order_id | customer | customer_phone | product | category | price | qty |
|---|---|---|---|---|---|---|
| 1 | Алиса | +7 900 111-11-11 | Ноутбук | Электроника | 90 000 | 1 |
| 1 | Алиса | +7 900 111-11-11 | Мышь | Электроника | 1 500 | 2 |
| 2 | Борис | +7 900 222-22-22 | Мышь | Электроника | 1 500 | 1 |

- **Аномалия обновления:** Алиса сменила телефон — его нужно исправить во всех её строках; пропущенная строка создаст противоречие.
- **Аномалия вставки:** нельзя добавить новый товар, пока его никто не заказал.
- **Аномалия удаления:** удалив единственный заказ Бориса, мы потеряем и его телефон.

## Функциональные зависимости

Нормальные формы формулируются через **функциональные зависимости**: столбец *B* зависит от *A*, если значение *A* однозначно определяет *B*. Здесь `customer → customer_phone`, `product → category, price`, а `(order_id, product) → qty`. Нормализация приводит таблицы к виду, где каждый неключевой столбец зависит от ключа — «от ключа, от всего ключа и ни от чего, кроме ключа».

## Нормальные формы

| Форма | Требование | Нарушение в примере |
|---|---|---|
| **1НФ** | все значения атомарны, нет повторяющихся групп и списков в ячейке | столбец «товары» со списком через запятую |
| **2НФ** | 1НФ, и неключевые столбцы зависят от *всего* составного ключа | `price` зависит только от `product`, а не от пары `(order_id, product)` |
| **3НФ** | 2НФ, и нет транзитивных зависимостей неключевых столбцов друг от друга | `customer_phone` зависит от `customer`, а не от ключа заказа |
| **НФБК** | каждый детерминант — потенциальный ключ | редкие случаи с перекрывающимися ключами |
| **4НФ, 5НФ** | нет многозначных зависимостей и зависимостей соединения | несколько независимых списков в одной таблице |

Четвёртую форму ввёл Рональд Фейгин в 1977 году;[3] понятное объяснение всех пяти форм дал Уильям Кент в статье «Простое руководство по пяти нормальным формам».[2] На практике чаще всего стремятся к **третьей нормальной форме** или НФБК.

## Нормализованная схема

```sql
CREATE TABLE customers (
    id    bigint PRIMARY KEY,
    name  text NOT NULL,
    phone text
);

CREATE TABLE products (
    id       bigint PRIMARY KEY,
    name     text NOT NULL UNIQUE,
    category text NOT NULL,
    price    numeric(12, 2) NOT NULL CHECK (price >= 0)
);

CREATE TABLE orders (
    id          bigint PRIMARY KEY,
    customer_id bigint NOT NULL REFERENCES customers(id),
    created_at  timestamptz NOT NULL DEFAULT now()
);

CREATE TABLE order_items (
    order_id   bigint NOT NULL REFERENCES orders(id),
    product_id bigint NOT NULL REFERENCES products(id),
    qty        int NOT NULL CHECK (qty > 0),
    unit_price numeric(12, 2) NOT NULL,          -- цена на момент покупки
    PRIMARY KEY (order_id, product_id)
);
```

Телефон хранится в одном месте, товар существует независимо от заказов, а связи обеспечиваются внешними ключами.[5] Обратите внимание на `unit_price`: это не дублирование, а другой факт — цена *в момент заказа*, которая не должна меняться вместе с текущей ценой товара.

## Денормализация

Нормализованная схема требует соединений (`JOIN`) при чтении, и на больших объёмах или в горячих запросах это может стать узким местом. Тогда часть данных дублируют сознательно:

- хранят вычисляемые итоги (сумма заказа, число комментариев) рядом с сущностью;
- копируют редко меняющиеся атрибуты, чтобы избежать соединения;
- строят материализованные представления и витрины для отчётов;
- в аналитических хранилищах используют схему «звезда» с широкими таблицами фактов (см. [Колоночное хранение](https://llmdocs.ru/wiki/columnar-storage.md)).

Денормализация переносит ответственность за согласованность на приложение, триггеры или процессы обновления, поэтому её применяют точечно — после того как узкое место подтверждено измерениями ([EXPLAIN и план запроса](https://llmdocs.ru/wiki/explain.md)), а не заранее.

## Нормализация и NoSQL

Документные базы ([MongoDB](https://llmdocs.ru/wiki/mongodb.md) и другие [NoSQL](https://llmdocs.ru/wiki/nosql.md)-системы) часто хранят связанные данные вложенными документами — по сути, денормализованно, — оптимизируя под конкретные сценарии чтения. Это удобно, когда данные читаются целиком и редко меняются по частям, но аномалии обновления никуда не исчезают: их просто приходится решать в коде.

## Практические советы

- Начинайте с нормализованной схемы (3НФ) и денормализуйте по результатам измерений.
- Выражайте правила ограничениями — `PRIMARY KEY`, `UNIQUE`, `FOREIGN KEY`, `CHECK` — чтобы база сама защищала целостность.
- Не храните списки в одной ячейке через запятую — для связи «многие ко многим» нужна отдельная таблица.
- Изменения схемы проводите [миграциями](https://llmdocs.ru/wiki/schema-migrations.md). Краткое введение в основы нормализации есть в документации Microsoft.[4]

## См. также

- [Реляционная база данных](https://llmdocs.ru/wiki/relational-database.md)
- [SQL](https://llmdocs.ru/wiki/sql.md)
- [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md)
- [Миграции схемы БД](https://llmdocs.ru/wiki/schema-migrations.md)
- [NoSQL](https://llmdocs.ru/wiki/nosql.md)

## Источники

1. [E. F. Codd — A Relational Model of Data for Large Shared Data Banks (CACM, 1970)](https://dl.acm.org/doi/10.1145/362384.362685)
2. [W. Kent — A Simple Guide to Five Normal Forms in Relational Database Theory (1983)](https://www.bkent.net/Doc/simple5.htm)
3. [R. Fagin — Multivalued Dependencies and a New Normal Form for Relational Databases (1977)](https://dl.acm.org/doi/10.1145/320557.320571)
4. [Microsoft Learn — Description of the database normalization basics](https://learn.microsoft.com/en-us/office/troubleshoot/access/database-normalization-description)
5. [PostgreSQL Documentation — Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html)
